mirror of
https://github.com/digarok/gsplus.git
synced 2024-05-28 13:41:31 +00:00
basically 0.14 updated with cmake, networking modules, and packaging via github actions - osx/ubuntu
This commit is contained in:
parent
df0833994a
commit
d28578f725
143
.github/workflows/release.yml
vendored
Normal file
143
.github/workflows/release.yml
vendored
Normal file
|
@ -0,0 +1,143 @@
|
|||
name: Create Release
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
# Maybe this should go after the successful build :P
|
||||
create-release:
|
||||
name: Create Release Job
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1.0.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}-testing
|
||||
draft: true
|
||||
prerelease: true
|
||||
# Workaround to preserve the release_url generated above for our next job
|
||||
- name: Store Release URL
|
||||
env:
|
||||
UPLOAD_URL: ${{ toJson( steps.create_release.outputs.upload_url )}}
|
||||
run: |
|
||||
echo "$UPLOAD_URL" > release_url.txt
|
||||
echo "UPLOAD_URL= $UPLOAD_URL"
|
||||
- name: Upload URL for later use
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: data
|
||||
path: release_url.txt
|
||||
|
||||
build-and-upload:
|
||||
name: Build
|
||||
needs: create-release
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ macos-latest, ubuntu-latest ]
|
||||
steps:
|
||||
- name: Download Release Data
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: data
|
||||
- name: Get Tag Name
|
||||
id: get_data
|
||||
shell: bash
|
||||
run: |
|
||||
URL=`cat data/release_url.txt | tr -d '"'`
|
||||
echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/}
|
||||
echo ::set-output name=RELEASE_URL::$URL
|
||||
echo "URL = $URL"
|
||||
echo name=SOURCE_TAG::${GITHUB_REF#refs/tags/}
|
||||
- uses: actions/checkout@v1
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Prep MacOSX
|
||||
if: matrix.os == 'macos-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.14
|
||||
# see: https://gist.github.com/fabianfett/fd811d7921eb856bb100c5c15565077f
|
||||
sudo xcode-select -s /Applications/Xcode_11.app/Contents/Developer
|
||||
xcode-select -p
|
||||
brew update
|
||||
|
||||
# BREW PACKAGES - Note we only seem to need to get the ones we link against for Mojave
|
||||
# dylibbundler--0.4.5.mojave.bottle.1.tar.gz
|
||||
# sdl2--2.0.10.mojave.bottle.1.tar.gz <--
|
||||
# freetype--2.10.1.mojave.bottle.1.tar.gz <--
|
||||
# sdl2_image--2.0.5.mojave.bottle.1.tar.gz <--
|
||||
# pkg-config--0.29.2.mojave.bottle.tar.gz
|
||||
|
||||
brew install dylibbundler
|
||||
brew install pkg-config
|
||||
|
||||
curl -L https://bintray.com/homebrew/bottles/download_file?file_path=sdl2-2.0.10.mojave.bottle.tar.gz -o sdl2-2.0.10.mojave.bottle.tar.gz
|
||||
brew install -f sdl2-2.0.10.mojave.bottle.tar.gz
|
||||
curl -L https://bintray.com/homebrew/bottles/download_file?file_path=sdl2_image-2.0.5.mojave.bottle.tar.gz -o sdl2_image-2.0.5.mojave.bottle.tar.gz
|
||||
brew install -f sdl2_image-2.0.5.mojave.bottle.tar.gz
|
||||
curl -L https://bintray.com/homebrew/bottles/download_file?file_path=freetype-2.10.1.mojave.bottle.tar.gz -o freetype-2.10.1.mojave.bottle.tar.gz
|
||||
brew install -f freetype-2.10.1.mojave.bottle.tar.gz
|
||||
- name: Prep Ubuntu
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
#sudo apt-get -y upgrade
|
||||
sudo apt-get -y install libpcap0.8-dev libfreetype6-dev libsdl2-dev libsdl2-image-dev
|
||||
|
||||
- name: Build MacOS/Ubuntu
|
||||
if: matrix.os != 'windows-latest'
|
||||
#working-directory: ./
|
||||
run: |
|
||||
echo "${{ matrix.os }} BUILD"
|
||||
mkdir build ; cd build
|
||||
cmake ..
|
||||
make
|
||||
pwd ; ls -al
|
||||
shell: bash
|
||||
# - name: Package NonWindows
|
||||
# if: matrix.os != 'windows-latest'
|
||||
# run: |
|
||||
# zip --junk-paths merlin32.zip Source/merlin32 README.md
|
||||
- name: Package MacOS
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: cd build ; chmod +x ../scripts/package-osx.sh ; ../scripts/package-osx.sh
|
||||
- name: Package Ubuntu
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
PACKAGE_DIR=gsplus-ubuntu-sdl
|
||||
mkdir $PACKAGE_DIR
|
||||
mkdir $PACKAGE_DIR/doc
|
||||
cp build/src/GSplus $PACKAGE_DIR/gsplus
|
||||
cp build/src/to_pro $PACKAGE_DIR/to_pro
|
||||
cp src/assets/config.txt $PACKAGE_DIR
|
||||
cp LICENSE.txt $PACKAGE_DIR/doc/
|
||||
cp doc/gsplusmanual.pdf $PACKAGE_DIR/doc/
|
||||
cp doc/README.txt $PACKAGE_DIR/doc/
|
||||
tar -cvjf gsplus-ubuntu-sdl.tar.bz2 $PACKAGE_DIR
|
||||
- name: Upload Release Asset MacOSX
|
||||
if: matrix.os == 'macos-latest'
|
||||
#id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.get_data.outputs.RELEASE_URL }}
|
||||
asset_path: ./build/GSplus-Install.dmg
|
||||
asset_name: ${{ format('GSplus-Install-{0}-{1}.dmg', matrix.os, steps.get_data.outputs.SOURCE_TAG ) }}
|
||||
asset_content_type: application/x-apple-diskimage
|
||||
- name: Upload Release Asset Ubuntu
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
#id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.get_data.outputs.RELEASE_URL }}
|
||||
asset_path: ./gsplus-ubuntu-sdl.tar.bz2
|
||||
asset_name: ${{ format('gsplus-ubuntu-sdl2-{0}.tar.bz2', steps.get_data.outputs.SOURCE_TAG ) }}
|
||||
asset_content_type: application/x-bzip2
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -25,4 +25,5 @@ images/
|
|||
screens/
|
||||
|
||||
# build tools that are often kept/tested locally as well as on the ci machines
|
||||
build/
|
||||
yoursway-create-dmg/
|
||||
|
|
9
CMakeLists.txt
Normal file
9
CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# set the project name and version
|
||||
project(gsplus VERSION 0.15)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
Copyright (C) 2016 - 2018 Dagen Brock
|
||||
Copyright (C) 2016 - 2020 Dagen Brock
|
||||
Copyright (C) 2010 - 2014 GSport contributors
|
||||
Copyright (C) 2003 Kent Dickey
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>gsplus</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>0.14, Copyright 2018 Dagen Brock</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>gsp-icons.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.dagenbrock.gsplus</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
</array>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>gsplus</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.14</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright 2018 Dagen Brock</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.3</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,5 +1,5 @@
|
|||
Package: gsplus
|
||||
Version: 0.14-0
|
||||
Version: 0.15-0
|
||||
Section: base
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
|
|
|
@ -23,3 +23,7 @@ git clone git@github.com:digarok/gsplus.git
|
|||
cd gsplus/src
|
||||
ln -s vars_osx_sdl2 vars
|
||||
make clean ; make
|
||||
|
||||
|
||||
# Packaging
|
||||
brew install dylibbundler
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
DEXTRAS=gsplus-osx/
|
||||
DDIR=$DEXTRAS/GSplus.app
|
||||
ADIR=assets
|
||||
mkdir -p $DEXTRAS/license
|
||||
mkdir -p $DDIR/Contents/MacOS
|
||||
mkdir -p $DDIR/Contents/Resources
|
||||
|
||||
cp gsplus $DDIR/Contents/MacOS
|
||||
cp config.txt $DDIR/Contents/MacOS
|
||||
cp $ADIR/Info.plist $DDIR/Contents
|
||||
cp $ADIR/gsp-icons.icns $DDIR/Contents/Resources
|
||||
dylibbundler -od -b -x $DDIR/Contents/MacOS/gsplus -d $DDIR/Contents/libs/
|
||||
|
||||
# files to include in dmg
|
||||
cp doc/gsplusmanual.pdf $DEXTRAS
|
||||
cp doc/README.txt $DEXTRAS
|
||||
cp LICENSE.txt $DEXTRAS/license
|
||||
cp COPYRIGHT.txt $DEXTRAS/license
|
||||
|
||||
# packaging now in DMG script
|
|
@ -1,21 +0,0 @@
|
|||
#!/bin/sh
|
||||
git clone https://github.com/andreyvit/yoursway-create-dmg.git
|
||||
cd yoursway-create-dmg
|
||||
|
||||
test -f GSplus-Install.dmg && rm GSplus-Install.dmg
|
||||
./create-dmg \
|
||||
--volname "GSplus" \
|
||||
--volicon "../assets/gsp-dmg-icons.icns" \
|
||||
--background "../assets/gsback.png" \
|
||||
--window-pos 200 120 \
|
||||
--window-size 710 600 \
|
||||
--icon-size 64 \
|
||||
--icon GSplus.app 250 210 \
|
||||
--hide-extension GSplus.app \
|
||||
--app-drop-link 440 210 \
|
||||
--icon README.txt 225 350 \
|
||||
--icon gsplusmanual.pdf 350 350 \
|
||||
--icon license 470 350 \
|
||||
GSplus-Install.dmg \
|
||||
../gsplus-osx/
|
||||
cp GSplus-Install.dmg ..
|
49
scripts/package-osx.sh
Executable file
49
scripts/package-osx.sh
Executable file
|
@ -0,0 +1,49 @@
|
|||
#!/bin/sh
|
||||
# run me from `build` subdirectory
|
||||
|
||||
# Create package directory and put any remaining files in place
|
||||
PDIR=package-osx
|
||||
rm -rf $PDIR #start empty
|
||||
mkdir $PDIR
|
||||
cp -r ../build/src/GSplus.app $PDIR
|
||||
|
||||
DDIR=$PDIR/GSplus.app
|
||||
|
||||
mkdir -p $PDIR/license
|
||||
cp ../LICENSE.txt $PDIR/license
|
||||
cp ../COPYRIGHT.txt $PDIR/license
|
||||
cp ../doc/gsplusmanual.pdf $PDIR
|
||||
cp ../doc/README.txt $PDIR
|
||||
|
||||
# Bundle dynamic libraries
|
||||
dylibbundler -od -b -x $DDIR/Contents/MacOS/gsplus -d $DDIR/Contents/libs/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# taken out DMG CI/CD for now as it requires keychain/UI interaction :(
|
||||
#exit
|
||||
|
||||
# Make DMG
|
||||
git clone https://github.com/digarok/create-dmg.git
|
||||
cd create-dmg
|
||||
|
||||
test -f GSplus-Install.dmg && rm GSplus-Install.dmg
|
||||
./create-dmg \
|
||||
--volname "GSplus" \
|
||||
--volicon "../../assets/gsp-dmg-icons.icns" \
|
||||
--background "../../assets/gsback.png" \
|
||||
--window-pos 200 120 \
|
||||
--window-size 710 600 \
|
||||
--icon-size 64 \
|
||||
--icon GSplus.app 250 210 \
|
||||
--hide-extension GSplus.app \
|
||||
--app-drop-link 440 210 \
|
||||
--icon README.txt 225 350 \
|
||||
--icon gsplusmanual.pdf 350 350 \
|
||||
--icon license 470 350 \
|
||||
--skip-jenkins \
|
||||
GSplus-Install.dmg \
|
||||
../package-osx/
|
||||
mv GSplus-Install.dmg ..
|
263
src/CMakeLists.txt
Normal file
263
src/CMakeLists.txt
Normal file
|
@ -0,0 +1,263 @@
|
|||
|
||||
INCLUDE (CheckFunctionExists)
|
||||
INCLUDE (CheckLibraryExists)
|
||||
INCLUDE (CheckTypeSize)
|
||||
INCLUDE (CheckIncludeFile)
|
||||
INCLUDE (CheckCSourceCompiles)
|
||||
|
||||
INCLUDE (FindPkgConfig)
|
||||
INCLUDE (TestBigEndian)
|
||||
|
||||
|
||||
set(PACKAGE_NAME "GSplus")
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED TRUE)
|
||||
|
||||
set(__MSVC__ ${MSVC})
|
||||
set(__CLANG__ FALSE)
|
||||
set(__GCC__ FALSE)
|
||||
|
||||
if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
set(__CLANG__ TRUE)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
set(__GCC__ TRUE)
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(__CLANG__)
|
||||
add_compile_options(
|
||||
-Wall -fomit-frame-pointer
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
if(__GCC__)
|
||||
add_compile_options(
|
||||
-Wall -fomit-frame-pointer
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
|
||||
if(NOT IS_BIG_ENDIAN)
|
||||
add_definitions(-DGSPLUS_LITTLE_ENDIAN)
|
||||
endif()
|
||||
|
||||
|
||||
pkg_check_modules(SDL2 sdl2)
|
||||
pkg_check_modules(FREETYPE2 freetype2)
|
||||
|
||||
|
||||
find_program(PERL perl)
|
||||
|
||||
if (PERL-NOTFOUND)
|
||||
message(FATAL_ERROR "unable to find perl")
|
||||
endif()
|
||||
|
||||
|
||||
#
|
||||
# run ccmake, cmake -LH, or cmake -D...
|
||||
#
|
||||
set(DRIVER "SDL" CACHE STRING "Driver (SDL, X11, WIN32, FB, or HEADLESS")
|
||||
option(WITH_DEBUGGER "Enable the debugger" OFF)
|
||||
option(WITH_HOST_FST "Enable host fst support" ON)
|
||||
option(TOGGLE_STATUS "Enable F10 Toggle Status support (win32/x11)" OFF)
|
||||
option(WITH_RAWNET "Enable Uthernet emulation" OFF)
|
||||
option(WITH_ATBRIDGE "Enable AT Bridge" OFF)
|
||||
option(WITH_BACKTRACE "Enable PC Backtracing" OFF)
|
||||
option(WITH_STATIC "Enable static link" OFF)
|
||||
set(READLINE "AUTO" CACHE STRING "Readline library (AUTO, NONE, READLINE, LIBEDIT)")
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES string.h)
|
||||
check_function_exists(strcasecmp HAVE_STRCASECMP)
|
||||
check_function_exists(strncasecmp HAVE_STRNCASECMP)
|
||||
check_function_exists(strcasestr HAVE_STRCASESTR)
|
||||
|
||||
configure_file(string_extra.h.in string_extra.h)
|
||||
configure_file(version.h.in version.h)
|
||||
|
||||
set(generated_headers 8inst_c.h 16inst_c.h 8inst_s.h 16inst_s.h size_c.h size_s.h 8size_s.h 16size_s.h)
|
||||
add_custom_command(
|
||||
OUTPUT 8inst_c.h 16inst_c.h 8inst_s.h ${CMAKE_CURRENT_BINARY_DIR}/16inst_s.h
|
||||
COMMAND perl make_inst c 8 instable.h > ${CMAKE_CURRENT_BINARY_DIR}/8inst_c.h
|
||||
COMMAND perl make_inst c 16 instable.h > ${CMAKE_CURRENT_BINARY_DIR}/16inst_c.h
|
||||
COMMAND perl make_inst s 8 instable.h > ${CMAKE_CURRENT_BINARY_DIR}/8inst_s.h
|
||||
COMMAND perl make_inst s 16 instable.h > ${CMAKE_CURRENT_BINARY_DIR}/16inst_s.h
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/instable.h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT size_c.h size_s.h 8size_s.h 16size_s.h
|
||||
COMMAND perl make_size c size_tab.h > ${CMAKE_CURRENT_BINARY_DIR}/size_c.h
|
||||
COMMAND perl make_size s size_tab.h > ${CMAKE_CURRENT_BINARY_DIR}/size_s.h
|
||||
COMMAND perl make_size 8 size_tab.h > ${CMAKE_CURRENT_BINARY_DIR}/8size_s.h
|
||||
COMMAND perl make_size 16 size_tab.h > ${CMAKE_CURRENT_BINARY_DIR}/16size_s.h
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/size_tab.h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
|
||||
if (WITH_STATIC)
|
||||
if(__CLANG__ OR __GCC__)
|
||||
#add_link_options(-static) # 3.13
|
||||
link_libraries(-static)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
add_executable(to_pro to_pro.c)
|
||||
#add_executable(partls partls.c)
|
||||
|
||||
add_subdirectory(atbridge)
|
||||
#add_subdirectory(tfe)
|
||||
add_subdirectory(rawnet)
|
||||
|
||||
if (DRIVER MATCHES "SDL")
|
||||
set(driver_code sdl2_driver.c sdl2snd_driver.c)
|
||||
elseif(DRIVER MATCHES "X11")
|
||||
set(driver_code xdriver.c)
|
||||
elseif(DRIVER MATCHES "FB")
|
||||
set(driver_code fbdriver.c)
|
||||
elseif(DRIVER MATCHES "WIN32")
|
||||
set(driver_code win32snd_driver.c win_console.c win_generic.c)
|
||||
elseif(DRIVER MATCHES "HEADLESS")
|
||||
set(driver_code headless_driver.c)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid driver ${DRIVER}")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(host_fst_code host_common.c host_mli.c win32_host_fst.c win32_host_common.c)
|
||||
else()
|
||||
set(host_fst_code host_common.c host_mli.c host_fst.c unix_host_common.c)
|
||||
endif()
|
||||
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "" FORCE)
|
||||
|
||||
# https://cmake.org/cmake/help/latest/prop_tgt/MACOSX_BUNDLE_INFO_PLIST.html
|
||||
set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_VERSION}, Copyright 2020 Dagen Brock")
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2020 Dagen Brock")
|
||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING ${PROJECT_VERSION})
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION})
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION})
|
||||
set(MACOSX_BUNDLE_ICON_FILE gsp-icons.icns)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.dagenbrock.gsplus)
|
||||
|
||||
|
||||
# https://cmake.org/Wiki/CMake:Bundles_And_Frameworks
|
||||
# OS X properties.
|
||||
add_executable(GSplus WIN32 MACOSX_BUNDLE
|
||||
adb.c clock.c config.c engine_c.c scc.c iwm.c
|
||||
joystick_driver.c moremem.c paddles.c parallel.c printer.cpp sim65816.c
|
||||
smartport.c sound.c sound_driver.c video.c scc_socket_driver.c glog.c
|
||||
imagewriter.cpp scc_imagewriter.c scc_llap.c options.c
|
||||
|
||||
string_extra.c
|
||||
dis.c
|
||||
debug.c
|
||||
#$<$<BOOL:${WITH_DEBUGGER}>:debug.c>
|
||||
|
||||
$<$<BOOL:${WITH_HOST_FST}>:${host_fst_code}>
|
||||
${driver_code}
|
||||
${generated_headers}
|
||||
|
||||
|
||||
$<$<BOOL:${WIN32}>:scc_windriver.c>
|
||||
$<$<BOOL:${WIN32}>:win32.rc>
|
||||
$<$<BOOL:${APPLE}>:assets/config.txt>
|
||||
$<$<BOOL:${APPLE}>:assets/gsp-icons.icns>
|
||||
$<$<BOOL:${APPLE}>:assets/GSBug.Templates>
|
||||
$<$<BOOL:${APPLE}>:assets/NList.Data>
|
||||
$<$<BOOL:${APPLE}>:fix_mac_menu.m>
|
||||
)
|
||||
|
||||
|
||||
SET_SOURCE_FILES_PROPERTIES(
|
||||
assets/gsp-icons.icns
|
||||
PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources
|
||||
)
|
||||
|
||||
SET_SOURCE_FILES_PROPERTIES(
|
||||
assets/GSBug.Templates
|
||||
assets/NList.Data
|
||||
assets/config.txt
|
||||
PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources
|
||||
)
|
||||
|
||||
|
||||
if(APPLE)
|
||||
add_custom_command(TARGET GSplus POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/rawnet/vmnet_helper"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/GSplus.app/Contents/MacOS/vmnet_helper"
|
||||
)
|
||||
add_dependencies(GSplus vmnet_helper)
|
||||
endif()
|
||||
# SET_SOURCE_FILES_PROPERTIES(vmnet_helper PROPERTIES MACOSX_PACKAGE_LOCATION MacOS)
|
||||
|
||||
|
||||
if (WITH_RAWNET)
|
||||
target_link_libraries(GSplus rawnet)
|
||||
endif()
|
||||
|
||||
if (WITH_ATBRIDGE)
|
||||
target_link_libraries(GSplus atbridge)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(GSplus comdlg32 Shlwapi IPHlpApi
|
||||
winmm gdi32 dsound comctl32 ws2_32 shell32
|
||||
)
|
||||
endif()
|
||||
|
||||
if (DRIVER MATCHES "SDL")
|
||||
target_link_libraries(GSplus ${SDL2_LDFLAGS} ${FREETYPE2_LDFLAGS} SDL2_image)
|
||||
target_compile_options(GSplus PUBLIC ${SDL2_CFLAGS} ${FREETYPE2_CFLAGS} -DHAVE_SDL)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
target_link_libraries(GSplus "-framework Cocoa")
|
||||
endif()
|
||||
|
||||
if (TOGGLE_STATUS)
|
||||
target_compile_definitions(GSplus PUBLIC TOGGLE_STATUS)
|
||||
endif()
|
||||
|
||||
if (WITH_BACKTRACE)
|
||||
target_compile_definitions(GSplus PUBLIC GSPLUS_BACKTRACE)
|
||||
endif()
|
||||
|
||||
if (WITH_DEBUGGER)
|
||||
target_compile_definitions(GSplus PRIVATE GSPLUS_DEBUGGER)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
#if (APPLE AND DRIVER MATCHES "SDL")
|
||||
# target_compile_options(GSplus PRIVATE -F${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
# target_link_libraries(GSplus -F${CMAKE_CURRENT_SOURCE_DIR} "-framework SDL2" -Wl,-rpath,@executable_path/../Frameworks)
|
||||
#endif()
|
||||
|
||||
|
||||
if (APPLE)
|
||||
add_custom_target(bundle
|
||||
DEPENDS GSplus
|
||||
COMMAND dylibbundler -od -b -x GSplus.app/Contents/MacOS/GSplus -d GSplus.app/Contents/libs
|
||||
COMMENT bundling libraries...
|
||||
)
|
||||
add_custom_target(setuid
|
||||
COMMAND sudo chown root GSplus.app/Contents/MacOS/vmnet_helper
|
||||
COMMAND sudo chmod +s GSplus.app/Contents/MacOS/vmnet_helper
|
||||
USES_TERMINAL)
|
||||
add_dependencies(setuid vmnet_helper)
|
||||
endif()
|
2556
src/assets/GSBug.Templates
Normal file
2556
src/assets/GSBug.Templates
Normal file
File diff suppressed because it is too large
Load Diff
2653
src/assets/NList.Data
Normal file
2653
src/assets/NList.Data
Normal file
File diff suppressed because it is too large
Load Diff
46
src/assets/config.txt
Normal file
46
src/assets/config.txt
Normal file
|
@ -0,0 +1,46 @@
|
|||
# GSplus configuration file version 0.15
|
||||
|
||||
s5d1 =
|
||||
s5d2 =
|
||||
|
||||
s6d1 =
|
||||
s6d2 =
|
||||
|
||||
s7d1 =
|
||||
|
||||
g_cfg_rom_path = ../../roms/gsrom3
|
||||
|
||||
|
||||
bram1[00] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[10] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[20] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[30] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[40] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[50] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[60] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[70] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[80] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[90] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[a0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[b0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[c0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[d0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[e0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[f0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
bram3[00] = 00 00 00 01 00 00 0d 06 02 01 01 00 01 00 00 00
|
||||
bram3[10] = 00 00 07 06 02 01 01 00 00 00 0f 06 06 00 05 06
|
||||
bram3[20] = 01 00 00 00 00 00 00 01 00 00 00 00 05 02 02 00
|
||||
bram3[30] = 00 00 2d 2d 00 00 00 00 00 00 02 02 02 06 08 00
|
||||
bram3[40] = 01 02 03 04 05 06 07 0a 00 01 02 03 04 05 06 07
|
||||
bram3[50] = 08 09 0a 0b 0c 0d 0e 0f 00 00 ff ff ff ff ff ff
|
||||
bram3[60] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
bram3[70] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
bram3[80] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
bram3[90] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
bram3[a0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
bram3[b0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
bram3[c0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
bram3[d0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
bram3[e0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
bram3[f0] = ff ff ff ff ff ff ff ff ff ff ff ff 36 2d 9c 87
|
9
src/atbridge/CMakeLists.txt
Normal file
9
src/atbridge/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
add_library(atbridge aarp.c atbridge.c elap.c llap.c pcap_delay.c port.c)
|
||||
|
||||
target_compile_definitions(atbridge PUBLIC HAVE_ATBRIDGE)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(atbridge ws2_32) # winsock2
|
||||
endif()
|
|
@ -17,7 +17,7 @@
|
|||
#include "aarp.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock.h>
|
||||
#include <winsock2.h>
|
||||
#elif __linux__
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "aarp.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock.h>
|
||||
#include <winsock2.h>
|
||||
#elif __linux__
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
#include "elap_defs.h"
|
||||
#include "pcap_delay.h"
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
#include <Windows.h>
|
||||
#include <NspAPI.h>
|
||||
#endif
|
||||
// #ifdef __CYGWIN__
|
||||
// #include <Windows.h>
|
||||
// #include <NspAPI.h>
|
||||
// #endif
|
||||
#ifdef WIN32
|
||||
#include <winsock.h>
|
||||
#include <winsock2.h>
|
||||
#include <IPHlpApi.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
|
|
|
@ -14,13 +14,7 @@ This wrapper provides a subset of the available PCAP APIs necessary for ATBridge
|
|||
Feel free to extend the wrapper.
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#include "../arch/win32/pcap.h"
|
||||
#elif __linux__
|
||||
#include <pcap.h>
|
||||
#elif __APPLE__
|
||||
#include <pcap/pcap.h>
|
||||
#endif
|
||||
|
||||
bool pcapdelay_load();
|
||||
bool pcapdelay_is_loaded();
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
# GSplus configuration file version 0.10a
|
||||
|
||||
s5d1 =
|
||||
s5d2 =
|
||||
|
||||
s6d1 =
|
||||
s6d2 =
|
||||
|
||||
s7d1 =
|
||||
|
||||
|
||||
|
||||
bram1[00] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[10] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[20] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[30] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[40] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[50] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[60] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[70] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[80] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[90] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[a0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[b0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[c0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[d0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[e0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[f0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
bram3[00] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[10] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[20] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[30] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[40] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[50] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[60] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[70] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[80] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[90] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[a0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[b0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[c0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[d0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[e0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[f0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
28
src/rawnet/CMakeLists.txt
Normal file
28
src/rawnet/CMakeLists.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
if(WIN32)
|
||||
set(rawnetarch rawnetarch_win32.c)
|
||||
elseif(APPLE)
|
||||
set(rawnetarch rawnetarch_vmnet_helper.c)
|
||||
#set(rawnetarch rawnetarch_unix.c)
|
||||
elseif(UNIX)
|
||||
set(rawnetarch rawnetarch_unix.c)
|
||||
endif()
|
||||
|
||||
add_library(rawnet cs8900.c rawnet.c rawnetsupp.c rawnetarch.c ${rawnetarch})
|
||||
|
||||
target_compile_definitions(rawnet PUBLIC HAVE_RAWNET)
|
||||
target_compile_definitions(rawnet PRIVATE CS8900_DEBUG RAWNET_DEBUG_FRAMES)
|
||||
|
||||
target_compile_options(rawnet PRIVATE -g)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(rawnet ws2_32) # winsock2
|
||||
elseif(APPLE)
|
||||
#target_link_libraries(rawnet PRIVATE pcap)
|
||||
#target_link_libraries(rawnet PRIVATE "-framework vmnet")
|
||||
add_executable(vmnet_helper vmnet_helper.c)
|
||||
target_link_libraries(vmnet_helper PRIVATE "-framework vmnet")
|
||||
|
||||
elseif(UNIX)
|
||||
target_link_libraries(rawnet PRIVATE pcap)
|
||||
endif()
|
35
src/rawnet/Networking.txt
Normal file
35
src/rawnet/Networking.txt
Normal file
|
@ -0,0 +1,35 @@
|
|||
Networking
|
||||
----------
|
||||
|
||||
GS+ can emulate an Uthernet (the original) card in slot 3. Marinetti is supported with the Uthernet Link Layer. Version 1.0.2 or newer is recommended.
|
||||
|
||||
Configuration:
|
||||
|
||||
In the settings menu, select Ethernet Card Configuration.
|
||||
|
||||
Make sure Uthernet Card in Slot 3 is set to On.
|
||||
|
||||
Select the Interface menu to choose the selected interface from a menu.
|
||||
|
||||
Win32:
|
||||
|
||||
Ethernet support uses Winpcap or its modern successor, npcap. You need to install them.
|
||||
|
||||
Winpcap/npcap require a hardwired ethernet connection in promiscuous mode -- they work by tapping into the ethernet stream.
|
||||
|
||||
Interface names are not particularly meaningful. Sorry. Run `getmac /v` from cmd.exe to get a human friendly name for the interface device.
|
||||
|
||||
In marinetti, hardcode the ip address, gateway, and dns servers.
|
||||
|
||||
OS X:
|
||||
|
||||
Ethernet support uses the vmnet framework. This provides a virtual ethernet device, dhcp server, and dns server, all bridged to the Macintosh's network.
|
||||
|
||||
Unfortunately, vmnet requires root permissions or a codesigning entitlment which may only valid for applications through the Mac App Store.
|
||||
|
||||
In marinetti, use DHCP.
|
||||
|
||||
Linux:
|
||||
|
||||
Ethernet support uses the tap ethernet device. This require setting up the device and bridging it to your local network.
|
||||
|
1675
src/rawnet/cs8900.c
Normal file
1675
src/rawnet/cs8900.c
Normal file
File diff suppressed because it is too large
Load Diff
64
src/rawnet/cs8900.h
Normal file
64
src/rawnet/cs8900.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* cs8900.h - CS8900 Ethernet Core
|
||||
*
|
||||
* Written by
|
||||
* Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
|
||||
*
|
||||
* This file is part of VICE, the Versatile Commodore Emulator.
|
||||
* See README for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef HAVE_RAWNET
|
||||
#error CS8900.H should not be included if HAVE_RAWNET is not defined!
|
||||
#endif /* #ifdef HAVE_RAWNET */
|
||||
|
||||
#ifndef VICE_CS8900_H
|
||||
#define VICE_CS8900_H
|
||||
|
||||
//#include <"types.h">
|
||||
|
||||
typedef struct snapshot_s snapshot_t;
|
||||
extern int cs8900_snapshot_read_module(snapshot_t *s);
|
||||
extern int cs8900_snapshot_write_module(snapshot_t *s);
|
||||
|
||||
extern int cs8900_init(void);
|
||||
extern void cs8900_reset(void);
|
||||
|
||||
extern int cs8900_activate(const char *net_interface);
|
||||
extern int cs8900_deactivate(void);
|
||||
extern void cs8900_shutdown(void);
|
||||
|
||||
extern uint8_t cs8900_read(uint16_t io_address);
|
||||
extern uint8_t cs8900_peek(uint16_t io_address);
|
||||
extern void cs8900_store(uint16_t io_address, uint8_t byte);
|
||||
extern int cs8900_dump(void);
|
||||
|
||||
/*
|
||||
This is a helper for cs8900_receive() to determine if the received frame should be accepted
|
||||
according to the settings.
|
||||
|
||||
This function is even allowed to be called (indirectly via rawnet_should_accept) in rawnetarch.c
|
||||
from rawnet_arch_receive() if necessary, and must be registered using rawnet_set_should_accept_func
|
||||
at init time.
|
||||
*/
|
||||
extern int cs8900_should_accept(unsigned char *buffer, int length, int *phashed, int *phash_index, int *pcorrect_mac, int *pbroadcast, int *pmulticast);
|
||||
|
||||
#endif
|
85
src/rawnet/rawnet.c
Normal file
85
src/rawnet/rawnet.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* rawnet.c - raw ethernet interface
|
||||
*
|
||||
* Written by
|
||||
* Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
|
||||
* Christian Vogelgsang <chris@vogelgsang.org>
|
||||
*
|
||||
* This file is part of VICE, the Versatile Commodore Emulator.
|
||||
* See README for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
// #include "vice.h"
|
||||
|
||||
#ifdef HAVE_RAWNET
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rawnet.h"
|
||||
#include "rawnetsupp.h"
|
||||
#include "rawnetarch.h"
|
||||
|
||||
static int (*should_accept)(unsigned char *, int, int *, int *, int *, int *, int *) = NULL;
|
||||
|
||||
int rawnet_should_accept(unsigned char *buffer, int length, int *phashed, int *phash_index, int *pcorrect_mac, int *pbroadcast, int *pmulticast)
|
||||
{
|
||||
assert(should_accept);
|
||||
return should_accept(buffer, length, phashed, phash_index, pcorrect_mac, pbroadcast, pmulticast);
|
||||
}
|
||||
|
||||
void rawnet_set_should_accept_func(int (*func)(unsigned char *, int, int *, int *, int *, int *, int *))
|
||||
{
|
||||
should_accept = func;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* functions for selecting and querying available NICs */
|
||||
|
||||
int rawnet_enumadapter_open(void)
|
||||
{
|
||||
if (!rawnet_arch_enumadapter_open()) {
|
||||
/* tfe_cannot_use = 1; */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rawnet_enumadapter(char **ppname, char **ppdescription)
|
||||
{
|
||||
return rawnet_arch_enumadapter(ppname, ppdescription);
|
||||
}
|
||||
|
||||
int rawnet_enumadapter_close(void)
|
||||
{
|
||||
return rawnet_arch_enumadapter_close();
|
||||
}
|
||||
|
||||
char *rawnet_get_standard_interface(void)
|
||||
{
|
||||
return rawnet_arch_get_standard_interface();
|
||||
}
|
||||
|
||||
int rawnet_status(void)
|
||||
{
|
||||
return rawnet_arch_status();
|
||||
}
|
||||
|
||||
#endif /* #ifdef HAVE_RAWNET */
|
77
src/rawnet/rawnet.h
Normal file
77
src/rawnet/rawnet.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* rawnet.h - raw ethernet interface
|
||||
*
|
||||
* Written by
|
||||
* Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
|
||||
*
|
||||
* This file is part of VICE, the Versatile Commodore Emulator.
|
||||
* See README for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_RAWNET
|
||||
#else
|
||||
#error RAWNET.H should not be included if HAVE_RAWNET is not defined!
|
||||
#endif /* #ifdef HAVE_RAWNET */
|
||||
|
||||
#ifndef VICE_RAWNET_H
|
||||
#define VICE_RAWNET_H
|
||||
|
||||
/*
|
||||
This is a helper for the _receive() function of the emulated ethernet chip to determine
|
||||
if the received frame should be accepted according to the settings.
|
||||
|
||||
This function is even allowed to be called in rawnetarch.c from rawnet_arch_receive() if
|
||||
necessary. the respective helper function of the emulated ethernet chip must be registered
|
||||
using rawnet_set_should_accept_func at init time.
|
||||
*/
|
||||
|
||||
extern int rawnet_should_accept(unsigned char *buffer, int length, int *phashed, int *phash_index, int *pcorrect_mac, int *pbroadcast, int *pmulticast);
|
||||
extern void rawnet_set_should_accept_func(int (*func)(unsigned char *, int, int *, int *, int *, int *, int *));
|
||||
|
||||
/*
|
||||
|
||||
These functions let the UI enumerate the available interfaces.
|
||||
|
||||
First, rawnet_enumadapter_open() is used to start enumeration.
|
||||
|
||||
rawnet_enumadapter() is then used to gather information for each adapter present
|
||||
on the system, where:
|
||||
|
||||
ppname points to a pointer which will hold the name of the interface
|
||||
ppdescription points to a pointer which will hold the description of the interface
|
||||
|
||||
For each of these parameters, new memory is allocated, so it has to be
|
||||
freed with lib_free().
|
||||
Note: The description can be NULL, since pcap_if_t.desc can be NULL, so
|
||||
check the description before calling lib_free() on it.
|
||||
|
||||
rawnet_enumadapter_close() must be used to stop processing.
|
||||
|
||||
Each function returns 1 on success, and 0 on failure.
|
||||
rawnet_enumadapter() only fails if there is no more adpater; in this case,
|
||||
*ppname and *ppdescription are not altered.
|
||||
*/
|
||||
extern int rawnet_enumadapter_open(void);
|
||||
extern int rawnet_enumadapter(char **ppname, char **ppdescription);
|
||||
extern int rawnet_enumadapter_close(void);
|
||||
extern char *rawnet_get_standard_interface(void);
|
||||
|
||||
extern int rawnet_status(void);
|
||||
|
||||
#endif
|
144
src/rawnet/rawnetarch.c
Normal file
144
src/rawnet/rawnetarch.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/** \file rawnetarch.c
|
||||
* \brief raw ethernet interface, architecture-dependant stuff
|
||||
*
|
||||
* \author Bas Wassink <b.wassink@ziggo.nl
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of VICE, the Versatile Commodore Emulator.
|
||||
* See README for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "rawnetarch.h"
|
||||
#include "rawnetsupp.h"
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAVE_RAWNET
|
||||
|
||||
/* backward compatibility junk */
|
||||
|
||||
|
||||
/** \brief Transmit a frame
|
||||
*
|
||||
* \param[in] force Delete waiting frames in transmit buffer
|
||||
* \param[in] onecoll Terminate after just one collision
|
||||
* \param[in] inhibit_crc Do not append CRC to the transmission
|
||||
* \param[in] tx_pad_dis Disable padding to 60 Bytes
|
||||
* \param[in] txlength Frame length
|
||||
* \param[in] txframe Pointer to the frame to be transmitted
|
||||
*/
|
||||
void rawnet_arch_transmit(int force, int onecoll, int inhibit_crc,
|
||||
int tx_pad_dis, int txlength, uint8_t *txframe)
|
||||
{
|
||||
|
||||
int ok;
|
||||
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message(rawnet_arch_log,
|
||||
"rawnet_arch_transmit() called, with: force = %s, onecoll = %s, "
|
||||
"inhibit_crc=%s, tx_pad_dis=%s, txlength=%u",
|
||||
force ? "TRUE" : "FALSE",
|
||||
onecoll ? "TRUE" : "FALSE",
|
||||
inhibit_crc ? "TRUE" : "FALSE",
|
||||
tx_pad_dis ? "TRUE" : "FALSE",
|
||||
txlength);
|
||||
#endif
|
||||
|
||||
ok = rawnet_arch_write(txframe, txlength);
|
||||
if (ok < 0) {
|
||||
log_message(rawnet_arch_log, "WARNING! Could not send packet!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if a frame was received
|
||||
*
|
||||
* This function checks if there was a frame received. If so, it returns 1,
|
||||
* else 0.
|
||||
*
|
||||
* If there was no frame, none of the parameters is changed!
|
||||
*
|
||||
* If there was a frame, the following actions are done:
|
||||
*
|
||||
* - at maximum \a plen byte are transferred into the buffer given by \a pbuffer
|
||||
* - \a plen gets the length of the received frame, EVEN if this is more
|
||||
* than has been copied to \a pbuffer!
|
||||
* - if the dest. address was accepted by the hash filter, \a phashed is set,
|
||||
* else cleared.
|
||||
* - if the dest. address was accepted by the hash filter, \a phash_index is
|
||||
* set to the number of the rule leading to the acceptance
|
||||
* - if the receive was ok (good CRC and valid length), \a *prx_ok is set, else
|
||||
* cleared.
|
||||
* - if the dest. address was accepted because it's exactly our MAC address
|
||||
* (set by rawnet_arch_set_mac()), \a pcorrect_mac is set, else cleared.
|
||||
* - if the dest. address was accepted since it was a broadcast address,
|
||||
* \a pbroadcast is set, else cleared.
|
||||
* - if the received frame had a crc error, \a pcrc_error is set, else cleared
|
||||
*
|
||||
* \param[out] buffer where to store a frame
|
||||
* \param[in,out] plen IN: maximum length of frame to copy;
|
||||
* OUT: length of received frame OUT
|
||||
* can be bigger than IN if received frame was
|
||||
* longer than supplied buffer
|
||||
* \param[out] phashed set if the dest. address is accepted by the
|
||||
* hash filter
|
||||
* \param[out] phash_index hash table index if hashed == TRUE
|
||||
* \param[out] prx_ok set if good CRC and valid length
|
||||
* \param[out] pcorrect_mac set if dest. address is exactly our IA
|
||||
* \param[out[ pbroadcast set if dest. address is a broadcast address
|
||||
* \param[out] pcrc_error set if received frame had a CRC error
|
||||
*/
|
||||
int rawnet_arch_receive(uint8_t *pbuffer, int *plen, int *phashed,
|
||||
int *phash_index, int *prx_ok, int *pcorrect_mac, int *pbroadcast,
|
||||
int *pcrc_error)
|
||||
{
|
||||
int ok;
|
||||
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message(rawnet_arch_log,
|
||||
"rawnet_arch_receive() called, with *plen=%u.",
|
||||
*plen);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
assert((*plen & 1) == 0);
|
||||
|
||||
ok = rawnet_arch_read(pbuffer, *plen);
|
||||
if (ok <= 0) return 0;
|
||||
|
||||
if (ok & 1) ++ok;
|
||||
*plen = ok;
|
||||
|
||||
*phashed =
|
||||
*phash_index =
|
||||
*pbroadcast =
|
||||
*pcorrect_mac =
|
||||
*pcrc_error = 0;
|
||||
|
||||
/* this frame has been received correctly */
|
||||
*prx_ok = 1;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* ifdef HAVE_RAWNET */
|
77
src/rawnet/rawnetarch.h
Normal file
77
src/rawnet/rawnetarch.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* rawnetarch.h - raw ethernet interface
|
||||
* architecture-dependant stuff
|
||||
*
|
||||
* Written by
|
||||
* Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
|
||||
*
|
||||
* This file is part of VICE, the Versatile Commodore Emulator.
|
||||
* See README for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef HAVE_RAWNET
|
||||
#else
|
||||
#error RAWNETARCH.H should not be included if HAVE_RAWNET is not defined!
|
||||
#endif /* #ifdef HAVE_RAWNET */
|
||||
|
||||
#ifndef VICE_RAWNETARCH_H
|
||||
#define VICE_RAWNETARCH_H
|
||||
|
||||
/* define this only if VICE should write each and every frame received
|
||||
and send into the VICE log
|
||||
WARNING: The log grows very fast!
|
||||
*/
|
||||
/* #define RAWNET_DEBUG_FRAMES */
|
||||
|
||||
// #include "types.h"
|
||||
|
||||
extern int rawnet_arch_init(void);
|
||||
extern void rawnet_arch_pre_reset(void);
|
||||
extern void rawnet_arch_post_reset(void);
|
||||
extern int rawnet_arch_activate(const char *interface_name);
|
||||
extern void rawnet_arch_deactivate(void);
|
||||
extern void rawnet_arch_set_mac(const uint8_t mac[6]);
|
||||
extern void rawnet_arch_set_hashfilter(const uint32_t hash_mask[2]);
|
||||
|
||||
extern void rawnet_arch_recv_ctl(int bBroadcast, int bIA, int bMulticast, int bCorrect, int bPromiscuous, int bIAHash);
|
||||
|
||||
extern void rawnet_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver);
|
||||
|
||||
extern void rawnet_arch_transmit(int force, int onecoll, int inhibit_crc, int tx_pad_dis, int txlength, uint8_t *txframe);
|
||||
|
||||
extern int rawnet_arch_receive(uint8_t *pbuffer, int *plen, int *phashed, int *phash_index, int *prx_ok, int *pcorrect_mac, int *pbroadcast, int *pcrc_error);
|
||||
|
||||
extern int rawnet_arch_enumadapter_open(void);
|
||||
extern int rawnet_arch_enumadapter(char **ppname, char **ppdescription);
|
||||
extern int rawnet_arch_enumadapter_close(void);
|
||||
|
||||
extern char *rawnet_arch_get_standard_interface(void);
|
||||
|
||||
|
||||
extern int rawnet_arch_read(void *buffer, int length);
|
||||
extern int rawnet_arch_write(const void *buffer, int length);
|
||||
|
||||
extern int rawnet_arch_get_mtu(void);
|
||||
extern int rawnet_arch_get_mac(uint8_t mac[6]);
|
||||
|
||||
extern int rawnet_arch_status(void);
|
||||
|
||||
#endif
|
481
src/rawnet/rawnetarch_tap.c
Normal file
481
src/rawnet/rawnetarch_tap.c
Normal file
|
@ -0,0 +1,481 @@
|
|||
/* tun/tap support */
|
||||
/* for Linux, *BSD */
|
||||
|
||||
/*
|
||||
* tap is a virtual ethernet devices.
|
||||
* open the device, configure, and read/write ethernet frames.
|
||||
*
|
||||
* Linux setup: (from Network Programmability and Automation, Appendix A)
|
||||
*
|
||||
* Notes:
|
||||
* - this assumes eth0 is your main interface device
|
||||
* - may need to install the iproute/iproute2 package (ip command)
|
||||
* - do this stuff as root.
|
||||
*
|
||||
* 1. create a tap interface
|
||||
* $ ip tuntap add tap65816 mode tap user YOUR_USER_NAME
|
||||
* $ ip link set tap65816 up
|
||||
*
|
||||
* 2. create a network bridge
|
||||
* $ ip link add name br0 type bridge
|
||||
* $ ip link set br0 up
|
||||
*
|
||||
* 3. bridge the physical network and virtual network.
|
||||
* $ ip link set eth0 master br0
|
||||
* $ ip link set tap65816 master br0
|
||||
*
|
||||
* 4. remove ip address from physical device (This will kill networking)
|
||||
* ip address flush dev eth0
|
||||
*
|
||||
* 5. and add the ip address to the bridge
|
||||
* dhclient br0 # if using dhcp
|
||||
* ip address add 192.168.1.1/24 dev eth0 # if using static ip address.
|
||||
*
|
||||
* *BSD:
|
||||
* - assumes eth0 is your main interface device.
|
||||
* $ ifconfig bridge0 create
|
||||
* $ ifconfig tap65816 create
|
||||
* $ ifconfig bridge0 addm eth0 addm tap65816 up
|
||||
*
|
||||
* allow normal users to open tap devices?
|
||||
* $ sysctl net.link.tap.user_open=1
|
||||
* $ sysctl net.link.tap.up_on_open=1
|
||||
*
|
||||
* set permissions
|
||||
* $ chown YOUR_USER_NAME /dev/tap65816
|
||||
* $ chmod 660 /dev/tap65816
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#endif
|
||||
|
||||
#include "rawnetarch.h"
|
||||
#include "rawnetsupp.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#define TAP_DEVICE "/dev/net/tun"
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#define TAP_DEVICE "/dev/tap"
|
||||
#endif
|
||||
|
||||
static int interface_fd = -1;
|
||||
static char *interface_dev = NULL;
|
||||
|
||||
static uint8_t interface_mac[6];
|
||||
static uint8_t interface_fake_mac[6];
|
||||
|
||||
static uint8_t *interface_buffer = NULL;
|
||||
static int interface_buffer_size = 0;
|
||||
|
||||
int rawnet_arch_init(void) {
|
||||
interface_fd = -1;
|
||||
return 1;
|
||||
}
|
||||
void rawnet_arch_pre_reset(void) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
void rawnet_arch_post_reset(void) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
/* memoized buffer for ethernet packets, etc */
|
||||
static int make_buffer(int size) {
|
||||
if (size <= interface_buffer_size) return 0;
|
||||
if (interface_buffer) free(interface_buffer);
|
||||
if (size < 1500) size = 1500; /* good mtu size */
|
||||
interface_buffer_size = 0;
|
||||
size *= 2;
|
||||
interface_buffer = malloc(size);
|
||||
if (!interface_buffer) return -1;
|
||||
interface_buffer_size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
/* interface name. default is tap65816. */
|
||||
int rawnet_arch_activate(const char *interface_name) {
|
||||
|
||||
struct ifreq ifr;
|
||||
|
||||
int ok;
|
||||
int one = 1;
|
||||
int fd;
|
||||
|
||||
if (!interface_name || !*interface_name) {
|
||||
interface_name = "tap65816";
|
||||
}
|
||||
|
||||
fd = open(TAP_DEVICE, O_RDWR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "rawnet_arch_activate: open(%s): %s\n", TAP_DEVICE, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ok = ioctl(fd, FIONBIO, &one);
|
||||
if (ok < 0) {
|
||||
perror("ioctl(FIONBIO");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(&if.ifr_name, interface_name);
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
ok = ioctl(fd, TUNSETIFF, (void *) &ifr);
|
||||
if (ok < 0) {
|
||||
perror("ioctl(TUNSETIFF)");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rawnet_arch_get_mac(interface_mac) < 0) {
|
||||
perror("rawnet_arch_get_mac");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
/* copy mac to fake mac */
|
||||
memcpy(interface_fake_mac, interface_mac, 6);
|
||||
|
||||
|
||||
interface_dev = strdup(interface_name);
|
||||
interface_fd = fd;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
/* man tap(4) */
|
||||
/* interface name. default is tap65816. */
|
||||
int rawnet_arch_activate(const char *interface_name) {
|
||||
|
||||
struct ifreq ifr;
|
||||
|
||||
int ok;
|
||||
int one = 1;
|
||||
int fd;
|
||||
char *path[64];
|
||||
|
||||
if (!interface_name || !*interface_name) {
|
||||
interface_name = "tap65816";
|
||||
}
|
||||
|
||||
ok = snprintf(path, sizeof(path), "/dev/%s", interface_name);
|
||||
if (ok >= sizeof(path)) return 0;
|
||||
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "rawnet_arch_activate: open(%s): %s\n", path, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ok = ioctl(fd, FIONBIO, &one);
|
||||
if (ok < 0) {
|
||||
perror("ioctl(FIONBIO");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rawnet_arch_get_mac(interface_mac) < 0) {
|
||||
perror("rawnet_arch_get_mac");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
/* copy mac to fake mac */
|
||||
memcpy(interface_fake_mac, interface_mac, 6);
|
||||
|
||||
|
||||
|
||||
interface_dev = strdup(interface_name);
|
||||
interface_fd = fd;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
void rawnet_arch_deactivate(void) {
|
||||
if (interface_fd >= 0)
|
||||
close(interface_fd);
|
||||
free(interface_dev);
|
||||
|
||||
free(interface_buffer);
|
||||
interface_buffer = 0;
|
||||
interface_buffer_size = 0;
|
||||
|
||||
interface_dev = NULL;
|
||||
interface_fd = -1;
|
||||
}
|
||||
|
||||
|
||||
void rawnet_arch_set_mac(const uint8_t mac[6]) {
|
||||
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message( rawnet_arch_log, "New MAC address set: %02X:%02X:%02X:%02X:%02X:%02X.", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
|
||||
#endif
|
||||
|
||||
memcpy(interface_fake_mac, mac, 6);
|
||||
|
||||
/* in theory, SIOCSIFHWADDR (linux) or SIOCSIFADDR (bsd) will set the mac address. */
|
||||
/* in testing, (linux) I get EBUSY or EOPNOTSUPP */
|
||||
|
||||
|
||||
#if 0
|
||||
if (interface_fd < 0) return;
|
||||
|
||||
|
||||
#if defined(__linux__)
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
|
||||
if (ioctl(interface_fd, SIOCSIFHWADDR, (void *)&ifr) < 0)
|
||||
perror("ioctl(SIOCSIFHWADDR)");
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
if (ioctl(interface_fd, SIOCSIFADDR, mac) < 0)
|
||||
perror("ioctl(SIOCSIFADDR)");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
void rawnet_arch_set_hashfilter(const uint32_t hash_mask[2]) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
void rawnet_arch_recv_ctl(int bBroadcast, int bIA, int bMulticast, int bCorrect, int bPromiscuous, int bIAHash) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
void rawnet_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
int rawnet_arch_read(void *buffer, int nbyte) {
|
||||
int ok;
|
||||
|
||||
if (make_buffer(nbyte) < 0) return -1;
|
||||
|
||||
ok = read(interface_fd, interface_buffer, nbyte);
|
||||
if (ok <= 0) return -1;
|
||||
|
||||
rawnet_fix_incoming_packet(interface_buffer, ok, interface_mac, interface_fake_mac);
|
||||
memcpy(buffer, interface_buffer, ok);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int rawnet_arch_write(const void *buffer, int nbyte) {
|
||||
int ok;
|
||||
|
||||
if (make_buffer(nbyte) < 0) return -1;
|
||||
|
||||
|
||||
memcpy(interface_buffer, buffer, nbyte);
|
||||
rawnet_fix_outgoing_packet(interface_buffer, nbyte, interface_mac, interface_fake_mac);
|
||||
|
||||
ok = write(interface_fd, interface_buffer, nbyte);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
static unsigned adapter_index = 0;
|
||||
static unsigned adapter_count = 0;
|
||||
static char **devices = NULL;
|
||||
|
||||
static int cmp(const void *a, const void *b) {
|
||||
return strcasecmp(*(const char **)a, *(const char **)b);
|
||||
}
|
||||
|
||||
int rawnet_arch_enumadapter_open(void) {
|
||||
adapter_index = 0;
|
||||
adapter_count = 0;
|
||||
devices = NULL;
|
||||
|
||||
char buffer[MAXPATHLEN];
|
||||
|
||||
unsigned capacity = 0;
|
||||
unsigned count = 0;
|
||||
DIR *dp = NULL;
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
capacity = 20;
|
||||
devices = (char **)malloc(sizeof(char *) * capacity);
|
||||
if (!devices) return 0;
|
||||
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
dp = opendir("/sys/class/net/");
|
||||
if (!dp) goto fail;
|
||||
|
||||
for(;;) {
|
||||
char *cp;
|
||||
FILE *fp;
|
||||
struct dirent *d = readdir(dp);
|
||||
if (!d) break;
|
||||
|
||||
if (d->d_name[0] == '.') continue;
|
||||
|
||||
sprintf(buffer, "/sys/class/net/%s/tun_flags", d->d_name);
|
||||
fp = fopen(buffer, "r");
|
||||
if (!fp) continue;
|
||||
cp = fgets(buffer, sizeof(buffer), fp);
|
||||
fclose(fp);
|
||||
if (cp) {
|
||||
/* expect 0x1002 */
|
||||
int flags = strtol(cp, (char **)NULL, 16);
|
||||
if ((flags & TUN_TYPE_MASK) == IFF_TAP) {
|
||||
|
||||
devices[count++] = strdup(d->d_name);
|
||||
if (count == capacity) {
|
||||
char **tmp;
|
||||
capacity *= 2;
|
||||
tmp = (char **)realloc(devices, sizeof(char *) * capacity);
|
||||
if (tmp) devices = tmp;
|
||||
else break; /* no mem? */
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
closedir(dp);
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
/* dev/tapxxxx */
|
||||
dp = opendir("/dev/");
|
||||
if (!dp) goto fail;
|
||||
for(;;) {
|
||||
struct dirent *d = readdir(dp);
|
||||
if (!d) break;
|
||||
|
||||
if (d->d_name[0] == '.') continue;
|
||||
if (strncmp(d->d_name, "tap", 3) == 0 && isdigit(d->d_name[3])) {
|
||||
|
||||
devices[count++] = strdup(d->d_name);
|
||||
if (count == capacity) {
|
||||
char **tmp;
|
||||
capacity *= 2;
|
||||
tmp = (char **)realloc(devices, sizeof(char *) * capacity);
|
||||
if (tmp) devices = tmp;
|
||||
else break; /* no mem? */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
closedir(dp);
|
||||
#endif
|
||||
|
||||
/* sort them ... */
|
||||
qsort(devices, count, sizeof(char *), cmp);
|
||||
|
||||
adapter_count = count;
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (dp) closedir(dp);
|
||||
if (devices) for(i = 0; i <count; ++i) free(devices[i]);
|
||||
free(devices);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rawnet_arch_enumadapter_close(void) {
|
||||
|
||||
if (devices) {
|
||||
int i;
|
||||
for (i = 0; i < adapter_count; ++i)
|
||||
free(devices[i]);
|
||||
free(devices);
|
||||
}
|
||||
adapter_count = 0;
|
||||
adapter_index = 0;
|
||||
devices = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int rawnet_arch_enumadapter(char **ppname, char **ppdescription) {
|
||||
|
||||
if (adapter_index >= adapter_count) return 0;
|
||||
|
||||
if (ppdescription) *ppdescription = NULL;
|
||||
if (ppname) *ppname = strdup(devices[adapter_index]);
|
||||
++adapter_index;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
char *rawnet_arch_get_standard_interface(void) {
|
||||
return lib_stralloc("tap65816");
|
||||
}
|
||||
|
||||
int rawnet_arch_get_mtu(void) {
|
||||
if (interface_fd < 0) return -1;
|
||||
|
||||
#if defined(__linux__)
|
||||
/* n.b. linux tap driver doesn't actually support SIOCGIFMTU */
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
if (ioctl(interface_fd, SIOCGIFMTU, (void *) &ifr) < 0) return -1; /* ? */
|
||||
return ifr.ifr_mtu;
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
struct tapinfo ti;
|
||||
if (ioctl(interface_fd, TAPSIFINFO, &ti) < 0) return -1;
|
||||
return ti.mtu;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rawnet_arch_get_mac(uint8_t mac[6]) {
|
||||
|
||||
|
||||
if (interface_fd < 0) return -1;
|
||||
|
||||
#if defined(__linux__)
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
if (ioctl(interface_fd, SIOCGIFHWADDR, (void *)&ifr) < 0) return -1;
|
||||
memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
if (ioctl(interface_fd, SIOCSIFADDR, mac) < 0) return -1;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int rawnet_arch_status(void) {
|
||||
return interface_fd >= 0 ? 1 : 0;
|
||||
}
|
||||
|
511
src/rawnet/rawnetarch_unix.c
Normal file
511
src/rawnet/rawnetarch_unix.c
Normal file
|
@ -0,0 +1,511 @@
|
|||
/** \file rawnetarch_unix.c
|
||||
* \brief Raw ethernet interface, architecture-dependent stuff
|
||||
*
|
||||
* \author Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
|
||||
* \author Bas Wassink <b.wassink@ziggo.nl>
|
||||
*
|
||||
* These functions let the UI enumerate the available interfaces.
|
||||
*
|
||||
* First, rawnet_arch_enumadapter_open() is used to start enumeration.
|
||||
*
|
||||
* rawnet_arch_enumadapter() is then used to gather information for each adapter
|
||||
* present on the system, where:
|
||||
*
|
||||
* ppname points to a pointer which will hold the name of the interface
|
||||
* ppdescription points to a pointer which will hold the description of the
|
||||
* interface
|
||||
*
|
||||
* For each of these parameters, new memory is allocated, so it has to be
|
||||
* freed with lib_free(), except ppdescription, which can be `NULL`, though
|
||||
* calling lib_free() on `NULL` is safe.
|
||||
*
|
||||
* rawnet_arch_enumadapter_close() must be used to stop processing.
|
||||
*
|
||||
* Each function returns 1 on success, and 0 on failure.
|
||||
* rawnet_arch_enumadapter() only fails if there is no more adpater; in this
|
||||
* case, *ppname and *ppdescription are not altered.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of VICE, the Versatile Commodore Emulator.
|
||||
* See README for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// #include "vice.h"
|
||||
|
||||
#ifdef HAVE_RAWNET
|
||||
|
||||
#include <pcap.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// #include "lib.h"
|
||||
// #include "log.h"
|
||||
#include "rawnetarch.h"
|
||||
#include "rawnetsupp.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FIXME: rename all remaining tfe_ stuff to rawnet_
|
||||
*/
|
||||
|
||||
#define RAWNET_DEBUG_WARN 1 /* this should not be deactivated
|
||||
* If this should not be deactived, why is this
|
||||
* here at all? --compyx
|
||||
*/
|
||||
|
||||
|
||||
/** \brief Only select devices that are PCAP_IF_UP
|
||||
*
|
||||
* Since on Linux pcap_findalldevs() returns all interfaces, including special
|
||||
* kernal devices such as nfqueue, filtering the list returned by pcap makes
|
||||
* sense. Should this filtering cause trouble on other Unices, this define can
|
||||
* be guarded with #ifdef SOME_UNIX_VERSION to disable the filtering.
|
||||
*/
|
||||
#ifdef PCAP_IF_UP
|
||||
#define RAWNET_ONLY_IF_UP
|
||||
#endif
|
||||
|
||||
|
||||
/** #define RAWNET_DEBUG_ARCH 1 **/
|
||||
/** #define RAWNET_DEBUG_PKTDUMP 1 **/
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* variables needed */
|
||||
|
||||
// static log_t rawnet_arch_log = LOG_ERR;
|
||||
|
||||
|
||||
/** \brief Iterator for the list returned by pcap_findalldevs()
|
||||
*/
|
||||
static pcap_if_t *rawnet_pcap_dev_iter = NULL;
|
||||
|
||||
|
||||
/** \brief Device list returned by pcap_findalldevs()
|
||||
*
|
||||
* Can be `NULL` since pcap_findalldevs() considers not finding any devices a
|
||||
* succesful outcome.
|
||||
*/
|
||||
static pcap_if_t *rawnet_pcap_dev_list = NULL;
|
||||
|
||||
|
||||
static pcap_t *rawnet_pcap_fp = NULL;
|
||||
static char *rawnet_device_name = NULL;
|
||||
|
||||
|
||||
/** \brief Buffer for pcap error messages
|
||||
*/
|
||||
static char rawnet_pcap_errbuf[PCAP_ERRBUF_SIZE];
|
||||
|
||||
|
||||
#ifdef RAWNET_DEBUG_PKTDUMP
|
||||
|
||||
static void debug_output( const char *text, uint8_t *what, int count )
|
||||
{
|
||||
char buffer[256];
|
||||
char *p = buffer;
|
||||
char *pbuffer1 = what;
|
||||
int len1 = count;
|
||||
int i;
|
||||
|
||||
sprintf(buffer, "\n%s: length = %u\n", text, len1);
|
||||
fprintf(stderr, "%s", buffer);
|
||||
do {
|
||||
p = buffer;
|
||||
for (i=0; (i<8) && len1>0; len1--, i++) {
|
||||
sprintf(p, "%02x ", (unsigned int)(unsigned char)*pbuffer1++);
|
||||
p += 3;
|
||||
}
|
||||
*(p-1) = '\n'; *p = 0;
|
||||
fprintf(stderr, "%s", buffer);
|
||||
} while (len1>0);
|
||||
}
|
||||
#endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
|
||||
|
||||
|
||||
int rawnet_arch_enumadapter_open(void)
|
||||
{
|
||||
if (pcap_findalldevs(&rawnet_pcap_dev_list, rawnet_pcap_errbuf) == -1) {
|
||||
log_message(rawnet_arch_log,
|
||||
"ERROR in rawnet_arch_enumadapter_open: pcap_findalldevs: '%s'",
|
||||
rawnet_pcap_errbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!rawnet_pcap_dev_list) {
|
||||
log_message(rawnet_arch_log,
|
||||
"ERROR in rawnet_arch_enumadapter_open, finding all pcap "
|
||||
"devices - Do we have the necessary privilege rights?");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rawnet_pcap_dev_iter = rawnet_pcap_dev_list;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get current pcap device iterator values
|
||||
*
|
||||
* The \a ppname and \a ppdescription are heap-allocated via lib_stralloc()
|
||||
* and should thus be freed after use with lib_free(). Please not that
|
||||
* \a ppdescription can be `NULL` due to pcap_if_t->description being `NULL`,
|
||||
* so check against `NULL` before using it. Calling lib_free() on it is safe
|
||||
* though, free(`NULL`) is guaranteed to just do nothing.
|
||||
*
|
||||
* \param[out] ppname device name
|
||||
* \param[out] ppdescription device description
|
||||
*
|
||||
* \return bool (1 on success, 0 on failure)
|
||||
*/
|
||||
int rawnet_arch_enumadapter(char **ppname, char **ppdescription)
|
||||
{
|
||||
#ifdef RAWNET_ONLY_IF_UP
|
||||
/* only select devices that are up */
|
||||
while (rawnet_pcap_dev_iter != NULL
|
||||
&& !(rawnet_pcap_dev_iter->flags & PCAP_IF_UP)) {
|
||||
rawnet_pcap_dev_iter = rawnet_pcap_dev_iter->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rawnet_pcap_dev_iter == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*ppname = lib_stralloc(rawnet_pcap_dev_iter->name);
|
||||
/* carefull: pcap_if_t->description can be NULL and lib_stralloc() fails on
|
||||
* passing `NULL` */
|
||||
if (rawnet_pcap_dev_iter->description != NULL) {
|
||||
*ppdescription = lib_stralloc(rawnet_pcap_dev_iter->description);
|
||||
} else {
|
||||
*ppdescription = NULL;
|
||||
}
|
||||
|
||||
rawnet_pcap_dev_iter = rawnet_pcap_dev_iter->next;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rawnet_arch_enumadapter_close(void)
|
||||
{
|
||||
if (rawnet_pcap_dev_list) {
|
||||
pcap_freealldevs(rawnet_pcap_dev_list);
|
||||
rawnet_pcap_dev_list = NULL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int rawnet_pcap_open_adapter(const char *interface_name)
|
||||
{
|
||||
rawnet_pcap_fp = pcap_open_live((char*)interface_name, 1700, 1, 20, rawnet_pcap_errbuf);
|
||||
if ( rawnet_pcap_fp == NULL) {
|
||||
log_message(rawnet_arch_log, "ERROR opening adapter: '%s'", rawnet_pcap_errbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pcap_setnonblock(rawnet_pcap_fp, 1, rawnet_pcap_errbuf) < 0) {
|
||||
log_message(rawnet_arch_log, "WARNING: Setting PCAP to non-blocking failed: '%s'", rawnet_pcap_errbuf);
|
||||
}
|
||||
|
||||
/* Check the link layer. We support only Ethernet for simplicity. */
|
||||
if (pcap_datalink(rawnet_pcap_fp) != DLT_EN10MB) {
|
||||
log_message(rawnet_arch_log, "ERROR: TFE works only on Ethernet networks.");
|
||||
pcap_close(rawnet_pcap_fp);
|
||||
rawnet_pcap_fp = NULL;
|
||||
return 0;
|
||||
}
|
||||
rawnet_device_name = strdup(interface_name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* the architecture-dependend functions */
|
||||
|
||||
int rawnet_arch_init(void)
|
||||
{
|
||||
//rawnet_arch_log = log_open("TFEARCH");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void rawnet_arch_pre_reset(void)
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message( rawnet_arch_log, "rawnet_arch_pre_reset()." );
|
||||
#endif
|
||||
}
|
||||
|
||||
void rawnet_arch_post_reset(void)
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message( rawnet_arch_log, "rawnet_arch_post_reset()." );
|
||||
#endif
|
||||
}
|
||||
|
||||
int rawnet_arch_activate(const char *interface_name)
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message( rawnet_arch_log, "rawnet_arch_activate()." );
|
||||
#endif
|
||||
if (!rawnet_pcap_open_adapter(interface_name)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void rawnet_arch_deactivate( void )
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message( rawnet_arch_log, "rawnet_arch_deactivate()." );
|
||||
#endif
|
||||
}
|
||||
|
||||
void rawnet_arch_set_mac( const uint8_t mac[6] )
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message( rawnet_arch_log, "New MAC address set: %02X:%02X:%02X:%02X:%02X:%02X.", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
|
||||
#endif
|
||||
}
|
||||
|
||||
void rawnet_arch_set_hashfilter(const uint32_t hash_mask[2])
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message( rawnet_arch_log, "New hash filter set: %08X:%08X.", hash_mask[1], hash_mask[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* int bBroadcast - broadcast */
|
||||
/* int bIA - individual address (IA) */
|
||||
/* int bMulticast - multicast if address passes the hash filter */
|
||||
/* int bCorrect - accept correct frames */
|
||||
/* int bPromiscuous - promiscuous mode */
|
||||
/* int bIAHash - accept if IA passes the hash filter */
|
||||
|
||||
void rawnet_arch_recv_ctl(int bBroadcast, int bIA, int bMulticast, int bCorrect, int bPromiscuous, int bIAHash)
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message(rawnet_arch_log, "rawnet_arch_recv_ctl() called with the following parameters:" );
|
||||
log_message(rawnet_arch_log, "\tbBroadcast = %s", bBroadcast ? "TRUE" : "FALSE");
|
||||
log_message(rawnet_arch_log, "\tbIA = %s", bIA ? "TRUE" : "FALSE");
|
||||
log_message(rawnet_arch_log, "\tbMulticast = %s", bMulticast ? "TRUE" : "FALSE");
|
||||
log_message(rawnet_arch_log, "\tbCorrect = %s", bCorrect ? "TRUE" : "FALSE");
|
||||
log_message(rawnet_arch_log, "\tbPromiscuous = %s", bPromiscuous ? "TRUE" : "FALSE");
|
||||
log_message(rawnet_arch_log, "\tbIAHash = %s", bIAHash ? "TRUE" : "FALSE");
|
||||
#endif
|
||||
}
|
||||
|
||||
void rawnet_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver )
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message(rawnet_arch_log,
|
||||
"rawnet_arch_line_ctl() called with the following parameters:");
|
||||
log_message(rawnet_arch_log,
|
||||
"\tbEnableTransmitter = %s", bEnableTransmitter ? "TRUE" : "FALSE");
|
||||
log_message(rawnet_arch_log,
|
||||
"\tbEnableReceiver = %s", bEnableReceiver ? "TRUE" : "FALSE");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** \brief Raw pcap packet
|
||||
*/
|
||||
typedef struct rawnet_pcap_internal_s {
|
||||
unsigned int len; /**< length of packet data */
|
||||
uint8_t *buffer; /**< packet data */
|
||||
} rawnet_pcap_internal_t;
|
||||
|
||||
|
||||
/** \brief Callback function invoked by libpcap for every incoming packet
|
||||
*
|
||||
* \param[in,out] param reference to internal VICE packet struct
|
||||
* \param[in] header pcap header
|
||||
* \param[in] pkt_data packet data
|
||||
*/
|
||||
static void rawnet_pcap_packet_handler(u_char *param,
|
||||
const struct pcap_pkthdr *header, const u_char *pkt_data)
|
||||
{
|
||||
rawnet_pcap_internal_t *pinternal = (void*)param;
|
||||
|
||||
/* determine the count of bytes which has been returned,
|
||||
* but make sure not to overrun the buffer
|
||||
*/
|
||||
if (header->caplen < pinternal->len) {
|
||||
pinternal->len = header->caplen;
|
||||
}
|
||||
|
||||
memcpy(pinternal->buffer, pkt_data, pinternal->len);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Receives a frame
|
||||
*
|
||||
* If there's none, it returns a -1 in \a pinternal->len, if there is one,
|
||||
* it returns the length of the frame in bytes in \a pinternal->len.
|
||||
*
|
||||
* It copies the frame to \a buffer and returns the number of copied bytes as
|
||||
* the return value.
|
||||
*
|
||||
* \param[in,out] pinternal internal VICE packet struct
|
||||
*
|
||||
* \note At most 'len' bytes are copied.
|
||||
*
|
||||
* \return number of bytes copied or -1 on failure
|
||||
*/
|
||||
static int rawnet_arch_receive_frame(rawnet_pcap_internal_t *pinternal)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
/* check if there is something to receive */
|
||||
if (pcap_dispatch(rawnet_pcap_fp, 1, rawnet_pcap_packet_handler,
|
||||
(void*)pinternal) != 0) {
|
||||
/* Something has been received */
|
||||
ret = pinternal->len;
|
||||
}
|
||||
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message(rawnet_arch_log,
|
||||
"rawnet_arch_receive_frame() called, returns %d.", ret);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rawnet_arch_read(void *buffer, int nbyte) {
|
||||
|
||||
int len;
|
||||
|
||||
rawnet_pcap_internal_t internal = { nbyte, (uint8_t *)buffer };
|
||||
|
||||
len = rawnet_arch_receive_frame(&internal);
|
||||
|
||||
if (len <= 0) return len;
|
||||
|
||||
#ifdef RAWNET_DEBUG_PKTDUMP
|
||||
debug_output("Received frame: ", internal.buffer, internal.len);
|
||||
#endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int rawnet_arch_write(const void *buffer, int nbyte) {
|
||||
|
||||
#ifdef RAWNET_DEBUG_PKTDUMP
|
||||
debug_output("Transmit frame: ", buffer, nbyte);
|
||||
#endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
|
||||
|
||||
if (pcap_sendpacket(rawnet_pcap_fp, buffer, nbyte) < 0) {
|
||||
log_message(rawnet_arch_log, "WARNING! Could not send packet!");
|
||||
return -1;
|
||||
}
|
||||
return nbyte;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** \brief Find default device on which to capture
|
||||
*
|
||||
* \return name of standard interface
|
||||
*
|
||||
* \note pcap_lookupdev() has been deprecated, so the correct way to get
|
||||
* the default device is to use the first entry returned by
|
||||
* pcap_findalldevs().
|
||||
* See http://www.tcpdump.org/manpages/pcap_lookupdev.3pcap.html
|
||||
*
|
||||
* \return default interface name or `NULL` when not found
|
||||
*
|
||||
* \note free the returned value with lib_free() if not `NULL`
|
||||
*/
|
||||
char *rawnet_arch_get_standard_interface(void)
|
||||
{
|
||||
char *dev = NULL;
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
pcap_if_t *list;
|
||||
|
||||
if (pcap_findalldevs(&list, errbuf) == 0 && list != NULL) {
|
||||
dev = lib_stralloc(list[0].name);
|
||||
pcap_freealldevs(list);
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
extern int rawnet_arch_get_mtu(void) {
|
||||
|
||||
#if defined(__linux__)
|
||||
int fd;
|
||||
int ok;
|
||||
struct ifreq ifr;
|
||||
|
||||
if (!rawnet_device_name) return -1;
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, rawnet_device_name);
|
||||
ok = ioctl(fd, SIOCGIFMTU, (void *)&ifr);
|
||||
close(fd);
|
||||
if (ok < 0) return -1;
|
||||
return ifr.ifr_mtu;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern int rawnet_arch_get_mac(uint8_t mac[6]) {
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
int fd;
|
||||
struct ifreq ifr;
|
||||
int ok;
|
||||
|
||||
if (!rawnet_device_name) return -1;
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, rawnet_device_name);
|
||||
ok = ioctl(fd, SIOCGIFHWADDR, &ifr);
|
||||
close(fd);
|
||||
if (ok < 0) return -1;
|
||||
memcpy(mac, &ifr.ifr_hwaddr.sa_data, 6);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rawnet_arch_status(void) {
|
||||
return rawnet_pcap_fp ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* #ifdef HAVE_RAWNET */
|
281
src/rawnet/rawnetarch_vmnet.c
Normal file
281
src/rawnet/rawnetarch_vmnet.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* OS X 10.10+
|
||||
* vmnet support (clang -framework vmnet -framework Foundation)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <vmnet/vmnet.h>
|
||||
|
||||
#include "rawnetarch.h"
|
||||
#include "rawnetsupp.h"
|
||||
|
||||
|
||||
static interface_ref interface;
|
||||
static uint8_t interface_mac[6];
|
||||
static uint8_t interface_fake_mac[6];
|
||||
static uint64_t interface_mtu;
|
||||
static uint64_t interface_packet_size;
|
||||
static uint8_t *interface_buffer = NULL;
|
||||
static vmnet_return_t interface_status;
|
||||
|
||||
int rawnet_arch_init(void) {
|
||||
interface = NULL;
|
||||
return 1;
|
||||
}
|
||||
void rawnet_arch_pre_reset(void) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
void rawnet_arch_post_reset(void) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
int rawnet_arch_activate(const char *interface_name) {
|
||||
|
||||
xpc_object_t dict;
|
||||
dispatch_queue_t q;
|
||||
dispatch_semaphore_t sem;
|
||||
|
||||
/*
|
||||
* there's no way to set the MAC address directly.
|
||||
* using vmnet_interface_id_key w/ the previous interface id
|
||||
* *MIGHT* re-use the previous MAC address.
|
||||
*/
|
||||
|
||||
if (interface) return 1;
|
||||
|
||||
memset(interface_mac, 0, sizeof(interface_mac));
|
||||
memset(interface_fake_mac, 0, sizeof(interface_fake_mac));
|
||||
interface_status = 0;
|
||||
interface_mtu = 0;
|
||||
interface_packet_size = 0;
|
||||
|
||||
dict = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_uint64(dict, vmnet_operation_mode_key, VMNET_SHARED_MODE);
|
||||
sem = dispatch_semaphore_create(0);
|
||||
q = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
|
||||
|
||||
interface = vmnet_start_interface(dict, q, ^(vmnet_return_t status, xpc_object_t params){
|
||||
interface_status = status;
|
||||
if (status == VMNET_SUCCESS) {
|
||||
const char *cp;
|
||||
cp = xpc_dictionary_get_string(params, vmnet_mac_address_key);
|
||||
fprintf(stderr, "vmnet mac: %s\n", cp);
|
||||
sscanf(cp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
||||
&interface_mac[0],
|
||||
&interface_mac[1],
|
||||
&interface_mac[2],
|
||||
&interface_mac[3],
|
||||
&interface_mac[4],
|
||||
&interface_mac[5]
|
||||
);
|
||||
|
||||
interface_mtu = xpc_dictionary_get_uint64(params, vmnet_mtu_key);
|
||||
interface_packet_size = xpc_dictionary_get_uint64(params, vmnet_max_packet_size_key);
|
||||
|
||||
fprintf(stderr, "vmnet mtu: %u\n", (unsigned)interface_mtu);
|
||||
|
||||
}
|
||||
dispatch_semaphore_signal(sem);
|
||||
});
|
||||
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
if (interface_status == VMNET_SUCCESS) {
|
||||
interface_buffer = (uint8_t *)malloc(interface_packet_size);
|
||||
|
||||
/* copy mac to fake mac */
|
||||
memcpy(interface_fake_mac, interface_mac, 6);
|
||||
|
||||
} else {
|
||||
log_message(rawnet_arch_log, "vmnet_start_interface failed");
|
||||
if (interface) {
|
||||
vmnet_stop_interface(interface, q, ^(vmnet_return_t status){
|
||||
dispatch_semaphore_signal(sem);
|
||||
});
|
||||
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
|
||||
interface = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dispatch_release(sem);
|
||||
xpc_release(dict);
|
||||
return interface_status == VMNET_SUCCESS;
|
||||
}
|
||||
|
||||
void rawnet_arch_deactivate(void) {
|
||||
|
||||
dispatch_queue_t q;
|
||||
dispatch_semaphore_t sem;
|
||||
|
||||
|
||||
if (interface) {
|
||||
sem = dispatch_semaphore_create(0);
|
||||
q = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
|
||||
|
||||
vmnet_stop_interface(interface, q, ^(vmnet_return_t status){
|
||||
dispatch_semaphore_signal(sem);
|
||||
});
|
||||
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
|
||||
dispatch_release(sem);
|
||||
|
||||
interface = NULL;
|
||||
interface_status = 0;
|
||||
}
|
||||
free(interface_buffer);
|
||||
interface_buffer = NULL;
|
||||
|
||||
}
|
||||
|
||||
void rawnet_arch_set_mac(const uint8_t mac[6]) {
|
||||
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message( rawnet_arch_log, "New MAC address set: %02X:%02X:%02X:%02X:%02X:%02X.", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
|
||||
#endif
|
||||
memcpy(interface_fake_mac, mac, 6);
|
||||
}
|
||||
void rawnet_arch_set_hashfilter(const uint32_t hash_mask[2]) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
void rawnet_arch_recv_ctl(int bBroadcast, int bIA, int bMulticast, int bCorrect, int bPromiscuous, int bIAHash) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
void rawnet_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
|
||||
int rawnet_arch_read(void *buffer, int nbyte) {
|
||||
|
||||
int count = 1;
|
||||
int xfer;
|
||||
vmnet_return_t st;
|
||||
struct vmpktdesc v;
|
||||
struct iovec iov;
|
||||
|
||||
iov.iov_base = interface_buffer;
|
||||
iov.iov_len = interface_packet_size;
|
||||
|
||||
v.vm_pkt_size = interface_packet_size;
|
||||
v.vm_pkt_iov = &iov;
|
||||
v.vm_pkt_iovcnt = 1;
|
||||
v.vm_flags = 0;
|
||||
|
||||
st = vmnet_read(interface, &v, &count);
|
||||
if (st != VMNET_SUCCESS) {
|
||||
log_message(rawnet_arch_log, "vmnet_read failed!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (count < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rawnet_fix_incoming_packet(interface_buffer, v.vm_pkt_size, interface_mac, interface_fake_mac);
|
||||
|
||||
// iov.iov_len is not updated with the read count, apparently.
|
||||
/* don't sebug multicast packets */
|
||||
if (interface_buffer[0] == 0xff || (interface_buffer[0] & 0x01) == 0 ) {
|
||||
fprintf(stderr, "\nrawnet_arch_receive: %u\n", (unsigned)v.vm_pkt_size);
|
||||
rawnet_hexdump(interface_buffer, v.vm_pkt_size);
|
||||
}
|
||||
|
||||
xfer = v.vm_pkt_size;
|
||||
memcpy(buffer, interface_buffer, xfer);
|
||||
|
||||
return xfer;
|
||||
}
|
||||
|
||||
int rawnet_arch_write(const void *buffer, int nbyte) {
|
||||
|
||||
int count = 1;
|
||||
vmnet_return_t st;
|
||||
struct vmpktdesc v;
|
||||
struct iovec iov;
|
||||
|
||||
if (nbyte <= 0) return 0;
|
||||
|
||||
if (nbyte > interface_packet_size) {
|
||||
log_message(rawnet_arch_log, "packet is too big: %d", nbyte);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* copy the buffer and fix the source mac address. */
|
||||
memcpy(interface_buffer, buffer, nbyte);
|
||||
rawnet_fix_outgoing_packet(interface_buffer, nbyte, interface_mac, interface_fake_mac);
|
||||
|
||||
iov.iov_base = interface_buffer;
|
||||
iov.iov_len = nbyte;
|
||||
|
||||
v.vm_pkt_size = nbyte;
|
||||
v.vm_pkt_iov = &iov;
|
||||
v.vm_pkt_iovcnt = 1;
|
||||
v.vm_flags = 0;
|
||||
|
||||
|
||||
fprintf(stderr, "\nrawnet_arch_transmit: %u\n", (unsigned)iov.iov_len);
|
||||
rawnet_hexdump(interface_buffer, v.vm_pkt_size);
|
||||
|
||||
|
||||
st = vmnet_write(interface, &v, &count);
|
||||
|
||||
if (st != VMNET_SUCCESS) {
|
||||
log_message(rawnet_arch_log, "vmnet_write failed!");
|
||||
return -1;
|
||||
}
|
||||
return nbyte;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static unsigned adapter_index = 0;
|
||||
int rawnet_arch_enumadapter_open(void) {
|
||||
adapter_index = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rawnet_arch_enumadapter(char **ppname, char **ppdescription) {
|
||||
|
||||
if (adapter_index == 0) {
|
||||
++adapter_index;
|
||||
if (ppname) *ppname = lib_stralloc("vmnet");
|
||||
if (ppdescription) *ppdescription = lib_stralloc("vmnet");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rawnet_arch_enumadapter_close(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *rawnet_arch_get_standard_interface(void) {
|
||||
return lib_stralloc("vmnet");
|
||||
}
|
||||
|
||||
int rawnet_arch_get_mtu(void) {
|
||||
return interface ? interface_mtu : -1;
|
||||
}
|
||||
|
||||
int rawnet_arch_get_mac(uint8_t mac[6]) {
|
||||
if (interface) {
|
||||
memcpy(mac, interface_mac, 6);
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int rawnet_arch_status(void) {
|
||||
return interface ? 1 : 0;
|
||||
}
|
||||
|
512
src/rawnet/rawnetarch_vmnet_helper.c
Normal file
512
src/rawnet/rawnetarch_vmnet_helper.c
Normal file
|
@ -0,0 +1,512 @@
|
|||
/*
|
||||
* OS X 10.10+
|
||||
* vmnet support (clang -framework vmnet -framework Foundation)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <spawn.h>
|
||||
#include <err.h>
|
||||
#include <signal.h>
|
||||
#include <mach-o/dyld.h>
|
||||
|
||||
#include "rawnetarch.h"
|
||||
#include "rawnetsupp.h"
|
||||
|
||||
|
||||
enum {
|
||||
MSG_QUIT,
|
||||
MSG_STATUS,
|
||||
MSG_READ,
|
||||
MSG_WRITE
|
||||
};
|
||||
#define MAKE_MSG(msg, extra) (msg | ((extra) << 8))
|
||||
|
||||
static uint8_t interface_mac[6];
|
||||
static uint8_t interface_fake_mac[6];
|
||||
static uint32_t interface_mtu;
|
||||
static uint32_t interface_packet_size;
|
||||
static uint8_t *interface_buffer = NULL;
|
||||
|
||||
static pid_t interface_pid = 0;
|
||||
static int interface_pipe[2];
|
||||
|
||||
|
||||
static pid_t safe_waitpid(pid_t pid, int *stat_loc, int options) {
|
||||
for(;;) {
|
||||
pid_t rv = waitpid(pid, stat_loc,options);
|
||||
if (rv < 0 && errno == EINTR) continue;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t safe_read(void *data, size_t nbytes) {
|
||||
for (;;) {
|
||||
ssize_t rv = read(interface_pipe[0], data, nbytes);
|
||||
if (rv < 0 && errno == EINTR) continue;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t safe_readv(const struct iovec *iov, int iovcnt) {
|
||||
|
||||
for(;;) {
|
||||
ssize_t rv = readv(interface_pipe[0], iov, iovcnt);
|
||||
if (rv < 0 && errno == EINTR) continue;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ssize_t safe_write(const void *data, size_t nbytes) {
|
||||
for (;;) {
|
||||
ssize_t rv = write(interface_pipe[1], data, nbytes);
|
||||
if (rv < 0 && errno == EINTR) continue;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t safe_writev(const struct iovec *iov, int iovcnt) {
|
||||
|
||||
for(;;) {
|
||||
ssize_t rv = writev(interface_pipe[1], iov, iovcnt);
|
||||
if (rv < 0 && errno == EINTR) continue;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
/* block the sigpipe signal */
|
||||
static int block_pipe(struct sigaction *oact) {
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_handler = SIG_IGN;
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
return sigaction(SIGPIPE, &act, oact);
|
||||
}
|
||||
static int restore_pipe(const struct sigaction *oact) {
|
||||
return sigaction(SIGPIPE, oact, NULL);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int block_pipe(sigset_t *oldset) {
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGPIPE);
|
||||
sigaddset(&set, SIGCHLD);
|
||||
|
||||
return sigprocmask(SIG_BLOCK, &set, oldset);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int check_child_status(void) {
|
||||
pid_t pid;
|
||||
int stat;
|
||||
pid = safe_waitpid(interface_pid, &stat, WNOHANG);
|
||||
|
||||
if (pid < 0 && errno == ECHILD) {
|
||||
fprintf(stderr, "child process does not exist.\n");
|
||||
close(interface_pipe[0]);
|
||||
close(interface_pipe[1]);
|
||||
interface_pid = 0;
|
||||
return 0;
|
||||
}
|
||||
if (pid == interface_pid) {
|
||||
if (WIFEXITED(stat)) fprintf(stderr, "child process exited.\n");
|
||||
if (WIFSIGNALED(stat)) fprintf(stderr, "child process signalled.\n");
|
||||
|
||||
close(interface_pipe[0]);
|
||||
close(interface_pipe[1]);
|
||||
interface_pid = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *get_relative_path(const char *leaf) {
|
||||
|
||||
uint32_t size = 0;
|
||||
char *buffer = 0;
|
||||
int ok;
|
||||
char *cp;
|
||||
int l;
|
||||
|
||||
l = strlen(leaf);
|
||||
ok = _NSGetExecutablePath(NULL, &size);
|
||||
size += l + 1;
|
||||
buffer = malloc(size);
|
||||
if (buffer) {
|
||||
ok = _NSGetExecutablePath(buffer, &size);
|
||||
if (ok < 0) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
cp = strrchr(buffer, '/');
|
||||
if (cp)
|
||||
strcpy(cp + 1 , leaf);
|
||||
else {
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
int rawnet_arch_init(void) {
|
||||
//interface = NULL;
|
||||
return 1;
|
||||
}
|
||||
void rawnet_arch_pre_reset(void) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
void rawnet_arch_post_reset(void) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int rawnet_arch_activate(const char *interface_name) {
|
||||
|
||||
|
||||
int ok;
|
||||
|
||||
char *argv[] = { "vmnet_helper", NULL };
|
||||
char *path = NULL;
|
||||
|
||||
int pipe_stdin[2];
|
||||
int pipe_stdout[2];
|
||||
|
||||
struct sigaction oldaction;
|
||||
|
||||
|
||||
if (interface_pid > 0) return 1;
|
||||
|
||||
/* fd[0] = read, fd[1] = write */
|
||||
ok = pipe(pipe_stdin);
|
||||
if (ok < 0) { warn("pipe"); return 0; }
|
||||
|
||||
ok = pipe(pipe_stdout);
|
||||
if (ok < 0) { warn("pipe"); return 0; }
|
||||
|
||||
block_pipe(&oldaction);
|
||||
|
||||
#ifdef USE_POSIX_SPAWN
|
||||
posix_spawn_file_actions_t actions;
|
||||
posix_spawnattr_t attr;
|
||||
|
||||
posix_spawn_file_actions_init(&actions);
|
||||
posix_spawnattr_init(&attr);
|
||||
|
||||
|
||||
posix_spawn_file_actions_adddup2(&actions, pipe_stdin[0], STDIN_FILENO);
|
||||
posix_spawn_file_actions_adddup2(&actions, pipe_stdout[1], STDOUT_FILENO);
|
||||
|
||||
posix_spawn_file_actions_addclose(&actions, pipe_stdin[0]);
|
||||
posix_spawn_file_actions_addclose(&actions, pipe_stdin[1]);
|
||||
|
||||
posix_spawn_file_actions_addclose(&actions, pipe_stdout[0]);
|
||||
posix_spawn_file_actions_addclose(&actions, pipe_stdout[1]);
|
||||
|
||||
|
||||
path = get_relative_path("vmnet_helper");
|
||||
ok = posix_spawn(&interface_pid, path, &actions, &attr, argv, NULL);
|
||||
free(path);
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
posix_spawnattr_destroy(&attr);
|
||||
#else
|
||||
extern char **environ;
|
||||
/* need to setsid() on the child */
|
||||
path = get_relative_path("vmnet_helper");
|
||||
|
||||
interface_pid = fork();
|
||||
if (interface_pid < 0) ok = 0;
|
||||
if (interface_pid == 0) {
|
||||
|
||||
dup2(pipe_stdin[0], STDIN_FILENO);
|
||||
dup2(pipe_stdout[1], STDOUT_FILENO);
|
||||
|
||||
close(pipe_stdin[0]);
|
||||
close(pipe_stdin[1]);
|
||||
close(pipe_stdout[0]);
|
||||
close(pipe_stdout[1]);
|
||||
|
||||
setsid();
|
||||
execve(path, argv, environ);
|
||||
write(STDERR_FILENO, "execve failed\n", 14);
|
||||
_exit(1);
|
||||
}
|
||||
free(path);
|
||||
#endif
|
||||
close(pipe_stdin[0]);
|
||||
close(pipe_stdout[1]);
|
||||
/* posix spawn returns 0 on success, error code on failure. */
|
||||
|
||||
if (ok != 0) {
|
||||
fprintf(stderr, "posix_spawn vmnet_helper failed: %d\n", ok);
|
||||
close(pipe_stdin[1]);
|
||||
close(pipe_stdout[0]);
|
||||
interface_pid = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface_pipe[0] = pipe_stdout[0];
|
||||
interface_pipe[1] = pipe_stdin[1];
|
||||
|
||||
/* now get the mac/mtu/etc */
|
||||
|
||||
uint32_t msg = MAKE_MSG(MSG_STATUS, 0);
|
||||
ok = safe_write(&msg, 4);
|
||||
if (ok != 4) goto fail;
|
||||
|
||||
ok = safe_read(&msg, 4);
|
||||
if (ok != 4) goto fail;
|
||||
|
||||
if (msg != MAKE_MSG(MSG_STATUS, 6 + 4 + 4)) goto fail;
|
||||
|
||||
struct iovec iov[3];
|
||||
iov[0].iov_len = 6;
|
||||
iov[0].iov_base = interface_mac;
|
||||
iov[1].iov_len = 4;
|
||||
iov[1].iov_base = &interface_mtu;
|
||||
iov[2].iov_len = 4;
|
||||
iov[2].iov_base = &interface_packet_size;
|
||||
|
||||
ok = safe_readv(iov, 3);
|
||||
if (ok != 6 + 4 + 4) goto fail;
|
||||
|
||||
/* copy mac to fake mac */
|
||||
memcpy(interface_fake_mac, interface_mac, 6);
|
||||
|
||||
/* sanity check */
|
||||
/* expect MTU = 1500, packet_size = 1518 */
|
||||
if (interface_packet_size < 256) {
|
||||
interface_packet_size = 1518;
|
||||
}
|
||||
interface_buffer = malloc(interface_packet_size);
|
||||
if (!interface_buffer) goto fail;
|
||||
|
||||
restore_pipe(&oldaction);
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
close(interface_pipe[0]);
|
||||
close(interface_pipe[1]);
|
||||
safe_waitpid(interface_pid, NULL, 0);
|
||||
interface_pid = 0;
|
||||
|
||||
restore_pipe(&oldaction);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rawnet_arch_deactivate(void) {
|
||||
|
||||
if (interface_pid) {
|
||||
close(interface_pipe[0]);
|
||||
close(interface_pipe[1]);
|
||||
for(;;) {
|
||||
int ok = waitpid(interface_pid, NULL, 0);
|
||||
if (ok < 0 && errno == EINTR) continue;
|
||||
break;
|
||||
}
|
||||
interface_pid = 0;
|
||||
}
|
||||
free(interface_buffer);
|
||||
interface_buffer = NULL;
|
||||
}
|
||||
|
||||
void rawnet_arch_set_mac(const uint8_t mac[6]) {
|
||||
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message( rawnet_arch_log, "New MAC address set: %02X:%02X:%02X:%02X:%02X:%02X.", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
|
||||
#endif
|
||||
memcpy(interface_fake_mac, mac, 6);
|
||||
}
|
||||
void rawnet_arch_set_hashfilter(const uint32_t hash_mask[2]) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
void rawnet_arch_recv_ctl(int bBroadcast, int bIA, int bMulticast, int bCorrect, int bPromiscuous, int bIAHash) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
void rawnet_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver) {
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
|
||||
|
||||
int rawnet_arch_read(void *buffer, int nbyte) {
|
||||
|
||||
|
||||
uint32_t msg;
|
||||
int ok;
|
||||
int xfer;
|
||||
struct sigaction oldaction;
|
||||
|
||||
if (interface_pid <= 0) return -1;
|
||||
|
||||
block_pipe(&oldaction);
|
||||
|
||||
msg = MAKE_MSG(MSG_READ, 0);
|
||||
|
||||
ok = safe_write(&msg, 4);
|
||||
if (ok != 4) goto fail;
|
||||
|
||||
ok = safe_read(&msg, 4);
|
||||
if (ok != 4) goto fail;
|
||||
|
||||
if ((msg & 0xff) != MSG_READ) goto fail;
|
||||
|
||||
xfer = msg >> 8;
|
||||
if (xfer > interface_packet_size) {
|
||||
|
||||
fprintf(stderr, "packet size too big: %d\n", xfer);
|
||||
|
||||
/* drain the message ... */
|
||||
while (xfer) {
|
||||
int count = interface_packet_size;
|
||||
if (count > xfer) count = xfer;
|
||||
ok = safe_read(interface_buffer, count);
|
||||
if (ok < 0) goto fail;
|
||||
xfer -= ok;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xfer == 0) return -1;
|
||||
|
||||
ok = safe_read(interface_buffer, xfer);
|
||||
if (ok != xfer) goto fail;
|
||||
|
||||
|
||||
rawnet_fix_incoming_packet(interface_buffer, xfer, interface_mac, interface_fake_mac);
|
||||
|
||||
/* don't sebug multicast packets */
|
||||
if (interface_buffer[0] == 0xff || (interface_buffer[0] & 0x01) == 0 ) {
|
||||
fprintf(stderr, "\nrawnet_arch_receive: %u\n", (unsigned)xfer);
|
||||
rawnet_hexdump(interface_buffer, xfer);
|
||||
}
|
||||
|
||||
if (xfer > nbyte) xfer = nbyte;
|
||||
memcpy(buffer, interface_buffer, xfer);
|
||||
|
||||
restore_pipe(&oldaction);
|
||||
return xfer;
|
||||
|
||||
fail:
|
||||
/* check if process still ok? */
|
||||
check_child_status();
|
||||
restore_pipe(&oldaction);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rawnet_arch_write(const void *buffer, int nbyte) {
|
||||
|
||||
int ok;
|
||||
uint32_t msg;
|
||||
struct iovec iov[2];
|
||||
struct sigaction oldaction;
|
||||
|
||||
if (interface_pid <= 0) return -1;
|
||||
|
||||
|
||||
|
||||
if (nbyte <= 0) return 0;
|
||||
|
||||
if (nbyte > interface_packet_size) {
|
||||
log_message(rawnet_arch_log, "packet is too big: %d", nbyte);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* copy the buffer and fix the source mac address. */
|
||||
memcpy(interface_buffer, buffer, nbyte);
|
||||
rawnet_fix_outgoing_packet(interface_buffer, nbyte, interface_mac, interface_fake_mac);
|
||||
|
||||
|
||||
fprintf(stderr, "\nrawnet_arch_transmit: %u\n", (unsigned)nbyte);
|
||||
rawnet_hexdump(interface_buffer, nbyte);
|
||||
|
||||
|
||||
block_pipe(&oldaction);
|
||||
|
||||
msg = MAKE_MSG(MSG_WRITE, nbyte);
|
||||
|
||||
iov[0].iov_base = &msg;
|
||||
iov[0].iov_len = 4;
|
||||
iov[1].iov_base = interface_buffer;
|
||||
iov[1].iov_len = nbyte;
|
||||
|
||||
|
||||
ok = safe_writev(iov, 2);
|
||||
if (ok != 4 + nbyte) goto fail;
|
||||
|
||||
ok = safe_read(&msg, 4);
|
||||
if (ok != 4) goto fail;
|
||||
|
||||
if (msg != MAKE_MSG(MSG_WRITE, nbyte)) goto fail;
|
||||
|
||||
restore_pipe(&oldaction);
|
||||
return nbyte;
|
||||
|
||||
fail:
|
||||
check_child_status();
|
||||
restore_pipe(&oldaction);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static unsigned adapter_index = 0;
|
||||
int rawnet_arch_enumadapter_open(void) {
|
||||
adapter_index = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rawnet_arch_enumadapter(char **ppname, char **ppdescription) {
|
||||
|
||||
if (adapter_index == 0) {
|
||||
++adapter_index;
|
||||
if (ppname) *ppname = lib_stralloc("vmnet");
|
||||
if (ppdescription) *ppdescription = lib_stralloc("vmnet");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rawnet_arch_enumadapter_close(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *rawnet_arch_get_standard_interface(void) {
|
||||
return lib_stralloc("vmnet");
|
||||
}
|
||||
|
||||
int rawnet_arch_get_mtu(void) {
|
||||
return interface_pid > 0 ? interface_mtu : -1;
|
||||
}
|
||||
|
||||
int rawnet_arch_get_mac(uint8_t mac[6]) {
|
||||
if (interface_pid > 0) {
|
||||
memcpy(mac, interface_mac, 6);
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int rawnet_arch_status(void) {
|
||||
return interface_pid > 0 ? 1 : 0;
|
||||
}
|
||||
|
579
src/rawnet/rawnetarch_win32.c
Normal file
579
src/rawnet/rawnetarch_win32.c
Normal file
|
@ -0,0 +1,579 @@
|
|||
/** \file rawnetarch_win32.c
|
||||
* \brief Raw ethernet interface, Win32 stuff
|
||||
*
|
||||
* \author Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of VICE, the Versatile Commodore Emulator.
|
||||
* See README for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
// #include "vice.h"
|
||||
|
||||
#ifdef HAVE_RAWNET
|
||||
|
||||
/* #define WPCAP */
|
||||
|
||||
|
||||
|
||||
#include <pcap.h>
|
||||
/* prevent bpf redeclaration in packet32 */
|
||||
#ifndef BPF_MAJOR_VERSION
|
||||
#define BPF_MAJOR_VERSION
|
||||
#endif
|
||||
#include <Packet32.h>
|
||||
#include <Windows.h>
|
||||
#include <Ntddndis.h>
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// #include "lib.h"
|
||||
// #include "log.h"
|
||||
#include "rawnet.h"
|
||||
#include "rawnetarch.h"
|
||||
#include "rawnetsupp.h"
|
||||
|
||||
typedef pcap_t *(*pcap_open_live_t)(const char *, int, int, int, char *);
|
||||
typedef void *(*pcap_close_t)(pcap_t *);
|
||||
typedef int (*pcap_dispatch_t)(pcap_t *, int, pcap_handler, u_char *);
|
||||
typedef int (*pcap_setnonblock_t)(pcap_t *, int, char *);
|
||||
typedef int (*pcap_datalink_t)(pcap_t *);
|
||||
typedef int (*pcap_findalldevs_t)(pcap_if_t **, char *);
|
||||
typedef void (*pcap_freealldevs_t)(pcap_if_t *);
|
||||
typedef int (*pcap_sendpacket_t)(pcap_t *p, u_char *buf, int size);
|
||||
typedef char *(*pcap_lookupdev_t)(char *);
|
||||
|
||||
|
||||
typedef VOID (*PacketCloseAdapter_t)(LPADAPTER lpAdapter);
|
||||
typedef LPADAPTER (*PacketOpenAdapter_t)(PCHAR AdapterName);
|
||||
typedef BOOLEAN (*PacketSendPacket_t)(LPADAPTER AdapterObject, LPPACKET pPacket, BOOLEAN Sync);
|
||||
typedef BOOLEAN (*PacketRequest_t)(LPADAPTER AdapterObject, BOOLEAN Set, PPACKET_OID_DATA OidData);
|
||||
|
||||
|
||||
/** #define RAWNET_DEBUG_ARCH 1 **/
|
||||
/** #define RAWNET_DEBUG_PKTDUMP 1 **/
|
||||
|
||||
/* #define RAWNET_DEBUG_FRAMES - might be defined in rawnetarch.h ! */
|
||||
|
||||
#define RAWNET_DEBUG_WARN 1 /* this should not be deactivated */
|
||||
|
||||
static pcap_open_live_t p_pcap_open_live;
|
||||
static pcap_close_t p_pcap_close;
|
||||
static pcap_dispatch_t p_pcap_dispatch;
|
||||
static pcap_setnonblock_t p_pcap_setnonblock;
|
||||
static pcap_findalldevs_t p_pcap_findalldevs;
|
||||
static pcap_freealldevs_t p_pcap_freealldevs;
|
||||
static pcap_sendpacket_t p_pcap_sendpacket;
|
||||
static pcap_datalink_t p_pcap_datalink;
|
||||
static pcap_lookupdev_t p_pcap_lookupdev;
|
||||
|
||||
static PacketCloseAdapter_t p_PacketCloseAdapter;
|
||||
static PacketOpenAdapter_t p_PacketOpenAdapter;
|
||||
static PacketSendPacket_t p_PacketSendPacket;
|
||||
static PacketRequest_t p_PacketRequest;
|
||||
|
||||
static HINSTANCE pcap_library = NULL;
|
||||
static HINSTANCE packet_library = NULL;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* variables needed */
|
||||
|
||||
//static log_t rawnet_arch_log = LOG_ERR;
|
||||
|
||||
static pcap_if_t *EthernetPcapNextDev = NULL;
|
||||
static pcap_if_t *EthernetPcapAlldevs = NULL;
|
||||
static pcap_t *EthernetPcapFP = NULL;
|
||||
static char *rawnet_device_name = NULL;
|
||||
|
||||
static char EthernetPcapErrbuf[PCAP_ERRBUF_SIZE];
|
||||
|
||||
#ifdef RAWNET_DEBUG_PKTDUMP
|
||||
|
||||
static void debug_output(const char *text, uint8_t *what, int count)
|
||||
{
|
||||
char buffer[256];
|
||||
char *p = buffer;
|
||||
char *pbuffer1 = what;
|
||||
int len1 = count;
|
||||
int i;
|
||||
|
||||
sprintf(buffer, "\n%s: length = %u\n", text, len1);
|
||||
OutputDebugString(buffer);
|
||||
do {
|
||||
p = buffer;
|
||||
for (i = 0; (i < 8) && len1 > 0; len1--, i++) {
|
||||
sprintf( p, "%02x ", (unsigned int)(unsigned char)*pbuffer1++);
|
||||
p += 3;
|
||||
}
|
||||
*(p - 1) = '\n';
|
||||
*p = 0;
|
||||
OutputDebugString(buffer);
|
||||
} while (len1 > 0);
|
||||
}
|
||||
#endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
|
||||
|
||||
|
||||
static void EthernetPcapFreeLibrary(void)
|
||||
{
|
||||
if (pcap_library) {
|
||||
if (!FreeLibrary(pcap_library)) {
|
||||
log_message(rawnet_arch_log, "FreeLibrary WPCAP.DLL failed!");
|
||||
}
|
||||
pcap_library = NULL;
|
||||
|
||||
if (packet_library) FreeLibrary(packet_library);
|
||||
packet_library = NULL;
|
||||
|
||||
p_pcap_open_live = NULL;
|
||||
p_pcap_close = NULL;
|
||||
p_pcap_dispatch = NULL;
|
||||
p_pcap_setnonblock = NULL;
|
||||
p_pcap_findalldevs = NULL;
|
||||
p_pcap_freealldevs = NULL;
|
||||
p_pcap_sendpacket = NULL;
|
||||
p_pcap_datalink = NULL;
|
||||
p_pcap_lookupdev = NULL;
|
||||
|
||||
p_PacketOpenAdapter = NULL;
|
||||
p_PacketCloseAdapter = NULL;
|
||||
p_PacketSendPacket = NULL;
|
||||
p_PacketRequest = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* since I don't like typing too much... */
|
||||
#define GET_PROC_ADDRESS_AND_TEST( _name_ ) \
|
||||
p_##_name_ = (_name_##_t) GetProcAddress(x, #_name_); \
|
||||
if (!p_##_name_ ) { \
|
||||
log_message(rawnet_arch_log, "GetProcAddress " #_name_ " failed!"); \
|
||||
EthernetPcapFreeLibrary(); \
|
||||
return FALSE; \
|
||||
}
|
||||
|
||||
static BOOL EthernetPcapLoadLibrary(void)
|
||||
{
|
||||
/*
|
||||
* npcap is c:\System32\Npcap\wpcap.dll
|
||||
* winpcap is c:\System32\wpcap.dll
|
||||
*
|
||||
*/
|
||||
HINSTANCE x = NULL;
|
||||
if (!pcap_library) {
|
||||
/* This inserts c:\System32\Npcap\ into the search path. */
|
||||
char buffer[512];
|
||||
unsigned length;
|
||||
length = GetSystemDirectory(buffer, sizeof(buffer) - sizeof("\\Npcap"));
|
||||
if (length) {
|
||||
strcat(buffer + length, "\\Npcap");
|
||||
SetDllDirectory(buffer);
|
||||
}
|
||||
|
||||
pcap_library = LoadLibrary(TEXT("wpcap.dll"));
|
||||
|
||||
if (!pcap_library) {
|
||||
log_message(rawnet_arch_log, "LoadLibrary WPCAP.DLL failed!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
x = pcap_library;
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_open_live);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_close);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_dispatch);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_setnonblock);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_findalldevs);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_freealldevs);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_sendpacket);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_datalink);
|
||||
GET_PROC_ADDRESS_AND_TEST(pcap_lookupdev);
|
||||
}
|
||||
|
||||
if (!packet_library) {
|
||||
packet_library = LoadLibrary(TEXT("Packet.dll"));
|
||||
|
||||
if (!packet_library) {
|
||||
log_message(rawnet_arch_log, "LoadLibrary Packet.dll failed!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
x = packet_library;
|
||||
GET_PROC_ADDRESS_AND_TEST(PacketOpenAdapter);
|
||||
GET_PROC_ADDRESS_AND_TEST(PacketCloseAdapter);
|
||||
GET_PROC_ADDRESS_AND_TEST(PacketSendPacket);
|
||||
GET_PROC_ADDRESS_AND_TEST(PacketRequest);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef GET_PROC_ADDRESS_AND_TEST
|
||||
|
||||
|
||||
/*
|
||||
These functions let the UI enumerate the available interfaces.
|
||||
|
||||
First, rawnet_arch_enumadapter_open() is used to start enumeration.
|
||||
|
||||
rawnet_arch_enumadapter is then used to gather information for each adapter present
|
||||
on the system, where:
|
||||
|
||||
ppname points to a pointer which will hold the name of the interface
|
||||
ppdescription points to a pointer which will hold the description of the interface
|
||||
|
||||
For each of these parameters, new memory is allocated, so it has to be
|
||||
freed with lib_free().
|
||||
|
||||
rawnet_arch_enumadapter_close() must be used to stop processing.
|
||||
|
||||
Each function returns 1 on success, and 0 on failure.
|
||||
rawnet_arch_enumadapter() only fails if there is no more adpater; in this case,
|
||||
*ppname and *ppdescription are not altered.
|
||||
*/
|
||||
int rawnet_arch_enumadapter_open(void)
|
||||
{
|
||||
if (!EthernetPcapLoadLibrary()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((*p_pcap_findalldevs)(&EthernetPcapAlldevs, EthernetPcapErrbuf) == -1) {
|
||||
log_message(rawnet_arch_log, "ERROR in rawnet_arch_enumadapter_open: pcap_findalldevs: '%s'", EthernetPcapErrbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!EthernetPcapAlldevs) {
|
||||
log_message(rawnet_arch_log, "ERROR in rawnet_arch_enumadapter_open, finding all pcap devices - Do we have the necessary privilege rights?");
|
||||
return 0;
|
||||
}
|
||||
|
||||
EthernetPcapNextDev = EthernetPcapAlldevs;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rawnet_arch_enumadapter(char **ppname, char **ppdescription)
|
||||
{
|
||||
if (!EthernetPcapNextDev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*ppname = lib_stralloc(EthernetPcapNextDev->name);
|
||||
*ppdescription = lib_stralloc(EthernetPcapNextDev->description);
|
||||
|
||||
printf("%s: %s\n",
|
||||
EthernetPcapNextDev->name ? EthernetPcapNextDev->name : "",
|
||||
EthernetPcapNextDev->description ? EthernetPcapNextDev->description : ""
|
||||
);
|
||||
EthernetPcapNextDev = EthernetPcapNextDev->next;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rawnet_arch_enumadapter_close(void)
|
||||
{
|
||||
if (EthernetPcapAlldevs) {
|
||||
(*p_pcap_freealldevs)(EthernetPcapAlldevs);
|
||||
EthernetPcapAlldevs = NULL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL EthernetPcapOpenAdapter(const char *interface_name)
|
||||
{
|
||||
pcap_if_t *EthernetPcapDevice = NULL;
|
||||
|
||||
if (!rawnet_enumadapter_open()) {
|
||||
return FALSE;
|
||||
} else {
|
||||
/* look if we can find the specified adapter */
|
||||
char *pname;
|
||||
char *pdescription;
|
||||
BOOL found = FALSE;
|
||||
|
||||
if (interface_name) {
|
||||
/* we have an interface name, try it */
|
||||
EthernetPcapDevice = EthernetPcapAlldevs;
|
||||
|
||||
while (rawnet_enumadapter(&pname, &pdescription)) {
|
||||
if (strcmp(pname, interface_name) == 0) {
|
||||
found = TRUE;
|
||||
}
|
||||
lib_free(pname);
|
||||
lib_free(pdescription);
|
||||
if (found) break;
|
||||
EthernetPcapDevice = EthernetPcapNextDev;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
/* just take the first adapter */
|
||||
EthernetPcapDevice = EthernetPcapAlldevs;
|
||||
}
|
||||
}
|
||||
|
||||
EthernetPcapFP = (*p_pcap_open_live)(EthernetPcapDevice->name, 1700, 1, 20, EthernetPcapErrbuf);
|
||||
if (EthernetPcapFP == NULL) {
|
||||
log_message(rawnet_arch_log, "ERROR opening adapter: '%s'", EthernetPcapErrbuf);
|
||||
rawnet_enumadapter_close();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check the link layer. We support only Ethernet for simplicity. */
|
||||
if ((*p_pcap_datalink)(EthernetPcapFP) != DLT_EN10MB) {
|
||||
log_message(rawnet_arch_log, "ERROR: Ethernet works only on Ethernet networks.");
|
||||
rawnet_enumadapter_close();
|
||||
(*p_pcap_close)(EthernetPcapFP);
|
||||
EthernetPcapFP = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((*p_pcap_setnonblock)(EthernetPcapFP, 1, EthernetPcapErrbuf) < 0) {
|
||||
log_message(rawnet_arch_log, "WARNING: Setting PCAP to non-blocking failed: '%s'", EthernetPcapErrbuf);
|
||||
}
|
||||
|
||||
rawnet_device_name = strdup(EthernetPcapDevice->name);
|
||||
rawnet_enumadapter_close();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* the architecture-dependend functions */
|
||||
|
||||
int rawnet_arch_init(void)
|
||||
{
|
||||
//rawnet_arch_log = log_open("EthernetARCH");
|
||||
|
||||
if (!EthernetPcapLoadLibrary()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void rawnet_arch_pre_reset( void )
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message(rawnet_arch_log, "rawnet_arch_pre_reset().");
|
||||
#endif
|
||||
}
|
||||
|
||||
void rawnet_arch_post_reset( void )
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message(rawnet_arch_log, "rawnet_arch_post_reset().");
|
||||
#endif
|
||||
}
|
||||
|
||||
int rawnet_arch_activate(const char *interface_name)
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message(rawnet_arch_log, "rawnet_arch_activate().");
|
||||
#endif
|
||||
if (!EthernetPcapOpenAdapter(interface_name)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void rawnet_arch_deactivate( void )
|
||||
{
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message(rawnet_arch_log, "rawnet_arch_deactivate().");
|
||||
#endif
|
||||
}
|
||||
|
||||
void rawnet_arch_set_mac( const uint8_t mac[6] )
|
||||
{
|
||||
#if defined(RAWNET_DEBUG_ARCH) || defined(RAWNET_DEBUG_FRAMES)
|
||||
log_message(rawnet_arch_log, "New MAC address set: %02X:%02X:%02X:%02X:%02X:%02X.", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void rawnet_arch_set_hashfilter(const uint32_t hash_mask[2])
|
||||
{
|
||||
#if defined(RAWNET_DEBUG_ARCH) || defined(RAWNET_DEBUG_FRAMES)
|
||||
log_message(rawnet_arch_log, "New hash filter set: %08X:%08X.", hash_mask[1], hash_mask[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* int bBroadcast - broadcast */
|
||||
/* int bIA - individual address (IA) */
|
||||
/* int bMulticast - multicast if address passes the hash filter */
|
||||
/* int bCorrect - accept correct frames */
|
||||
/* int bPromiscuous - promiscuous mode */
|
||||
/* int bIAHash - accept if IA passes the hash filter */
|
||||
|
||||
|
||||
void rawnet_arch_recv_ctl(int bBroadcast, int bIA, int bMulticast, int bCorrect, int bPromiscuous, int bIAHash)
|
||||
{
|
||||
#if defined(RAWNET_DEBUG_ARCH) || defined(RAWNET_DEBUG_FRAMES)
|
||||
log_message(rawnet_arch_log, "rawnet_arch_recv_ctl() called with the following parameters:" );
|
||||
log_message(rawnet_arch_log, "\tbBroadcast = %s", bBroadcast ? "TRUE" : "FALSE" );
|
||||
log_message(rawnet_arch_log, "\tbIA = %s", bIA ? "TRUE" : "FALSE" );
|
||||
log_message(rawnet_arch_log, "\tbMulticast = %s", bMulticast ? "TRUE" : "FALSE" );
|
||||
log_message(rawnet_arch_log, "\tbCorrect = %s", bCorrect ? "TRUE" : "FALSE" );
|
||||
log_message(rawnet_arch_log, "\tbPromiscuous = %s", bPromiscuous ? "TRUE" : "FALSE" );
|
||||
log_message(rawnet_arch_log, "\tbIAHash = %s", bIAHash ? "TRUE" : "FALSE" );
|
||||
#endif
|
||||
}
|
||||
|
||||
void rawnet_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver)
|
||||
{
|
||||
#if defined(RAWNET_DEBUG_ARCH) || defined(RAWNET_DEBUG_FRAMES)
|
||||
log_message(rawnet_arch_log, "rawnet_arch_line_ctl() called with the following parameters:" );
|
||||
log_message(rawnet_arch_log, "\tbEnableTransmitter = %s", bEnableTransmitter ? "TRUE" : "FALSE" );
|
||||
log_message(rawnet_arch_log, "\tbEnableReceiver = %s", bEnableReceiver ? "TRUE" : "FALSE" );
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct Ethernet_PCAP_internal_s {
|
||||
unsigned int len;
|
||||
uint8_t *buffer;
|
||||
} Ethernet_PCAP_internal_t;
|
||||
|
||||
/* Callback function invoked by libpcap for every incoming packet */
|
||||
static void EthernetPcapPacketHandler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
|
||||
{
|
||||
Ethernet_PCAP_internal_t *pinternal = (void*)param;
|
||||
|
||||
/* determine the count of bytes which has been returned,
|
||||
* but make sure not to overrun the buffer
|
||||
*/
|
||||
if (header->caplen < pinternal->len) {
|
||||
pinternal->len = header->caplen;
|
||||
}
|
||||
|
||||
memcpy(pinternal->buffer, pkt_data, pinternal->len);
|
||||
}
|
||||
|
||||
/* the following function receives a frame.
|
||||
|
||||
If there's none, it returns a -1.
|
||||
If there is one, it returns the length of the frame in bytes.
|
||||
|
||||
It copies the frame to *buffer and returns the number of copied
|
||||
bytes as return value.
|
||||
|
||||
At most 'len' bytes are copied.
|
||||
*/
|
||||
static int rawnet_arch_receive_frame(Ethernet_PCAP_internal_t *pinternal)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
/* check if there is something to receive */
|
||||
if ((*p_pcap_dispatch)(EthernetPcapFP, 1, EthernetPcapPacketHandler, (void*)pinternal) != 0) {
|
||||
/* Something has been received */
|
||||
ret = pinternal->len;
|
||||
}
|
||||
|
||||
#ifdef RAWNET_DEBUG_ARCH
|
||||
log_message(rawnet_arch_log, "rawnet_arch_receive_frame() called, returns %d.", ret);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int rawnet_arch_read(void *buffer, int nbyte) {
|
||||
|
||||
int len;
|
||||
|
||||
Ethernet_PCAP_internal_t internal;
|
||||
|
||||
internal.len = nbyte;
|
||||
internal.buffer = (uint8_t *)buffer;
|
||||
|
||||
len = rawnet_arch_receive_frame(&internal);
|
||||
|
||||
if (len <= 0) return len;
|
||||
|
||||
#ifdef RAWNET_DEBUG_PKTDUMP
|
||||
debug_output("Received frame: ", internal.buffer, internal.len);
|
||||
#endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int rawnet_arch_write(const void *buffer, int nbyte) {
|
||||
|
||||
#ifdef RAWNET_DEBUG_PKTDUMP
|
||||
debug_output("Transmit frame: ", buffer, nbyte);
|
||||
#endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
|
||||
|
||||
if ((*p_pcap_sendpacket)(EthernetPcapFP, (u_char *)buffer, nbyte) == -1) {
|
||||
log_message(rawnet_arch_log, "WARNING! Could not send packet!");
|
||||
return -1;
|
||||
}
|
||||
return nbyte;
|
||||
}
|
||||
|
||||
|
||||
char *rawnet_arch_get_standard_interface(void)
|
||||
{
|
||||
char *dev, errbuf[PCAP_ERRBUF_SIZE];
|
||||
|
||||
if (!EthernetPcapLoadLibrary()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = lib_stralloc((*p_pcap_lookupdev)(errbuf));
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
extern int rawnet_arch_get_mtu(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern int rawnet_arch_get_mac(uint8_t mac[6]) {
|
||||
|
||||
int rv = -1;
|
||||
LPADAPTER outp = NULL;
|
||||
char buffer[sizeof(PACKET_OID_DATA) + 6];
|
||||
PPACKET_OID_DATA data = (PPACKET_OID_DATA)buffer;
|
||||
|
||||
|
||||
if (!packet_library) return -1;
|
||||
|
||||
/* 802.5 = token ring, 802.3 = wired ethernet */
|
||||
data->Oid = OID_802_3_CURRENT_ADDRESS; // OID_802_3_CURRENT_ADDRESS ? OID_802_3_PERMANENT_ADDRESS ?
|
||||
data->Length = 6;
|
||||
|
||||
|
||||
outp = p_PacketOpenAdapter(rawnet_device_name);
|
||||
if (!outp || outp->hFile == INVALID_HANDLE_VALUE) return -1;
|
||||
|
||||
if (p_PacketRequest(outp, FALSE, data)) {
|
||||
memcpy(mac, data->Data, 6);
|
||||
rv = 0;
|
||||
}
|
||||
p_PacketCloseAdapter(outp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int rawnet_arch_status(void) {
|
||||
return EthernetPcapFP ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* #ifdef HAVE_RAWNET */
|
372
src/rawnet/rawnetsupp.c
Normal file
372
src/rawnet/rawnetsupp.c
Normal file
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* This file is a consolidation of functions required for tfe
|
||||
* emulation taken from the following files
|
||||
*
|
||||
* lib.c - Library functions.
|
||||
* util.c - Miscellaneous utility functions.
|
||||
* crc32.c
|
||||
*
|
||||
* Written by
|
||||
* Andreas Boose <viceteam@t-online.de>
|
||||
* Ettore Perazzoli <ettore@comm2000.it>
|
||||
* Andreas Matthies <andreas.matthies@gmx.net>
|
||||
* Tibor Biczo <crown@mail.matav.hu>
|
||||
* Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>*
|
||||
*
|
||||
* This file is part of VICE, the Versatile Commodore Emulator.
|
||||
* See README for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "rawnetsupp.h"
|
||||
|
||||
|
||||
|
||||
#define CRC32_POLY 0xedb88320
|
||||
static unsigned long crc32_table[256];
|
||||
static int crc32_is_initialized = 0;
|
||||
|
||||
void lib_free(void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void *lib_malloc(size_t size) {
|
||||
|
||||
void *ptr = malloc(size);
|
||||
|
||||
if (ptr == NULL && size > 0) {
|
||||
perror("lib_malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/* Malloc enough space for `str', copy `str' into it and return its
|
||||
address. */
|
||||
char *lib_stralloc(const char *str) {
|
||||
char *ptr;
|
||||
|
||||
if (str == NULL) {
|
||||
fprintf(stderr, "lib_stralloc\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
ptr = strdup(str);
|
||||
if (!ptr) {
|
||||
perror("lib_stralloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Like realloc, but abort if not enough memory is available. */
|
||||
void *lib_realloc(void *ptr, size_t size) {
|
||||
|
||||
|
||||
void *new_ptr = realloc(ptr, size);
|
||||
|
||||
if (new_ptr == NULL) {
|
||||
perror("lib_realloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
// Util Stuff
|
||||
|
||||
/* Set a new value to the dynamically allocated string *str.
|
||||
Returns `-1' if nothing has to be done. */
|
||||
int util_string_set(char **str, const char *new_value) {
|
||||
if (*str == NULL) {
|
||||
if (new_value != NULL)
|
||||
*str = lib_stralloc(new_value);
|
||||
} else {
|
||||
if (new_value == NULL) {
|
||||
lib_free(*str);
|
||||
*str = NULL;
|
||||
} else {
|
||||
/* Skip copy if src and dest are already the same. */
|
||||
if (strcmp(*str, new_value) == 0)
|
||||
return -1;
|
||||
|
||||
*str = (char *)lib_realloc(*str, strlen(new_value) + 1);
|
||||
strcpy(*str, new_value);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// crc32 Stuff
|
||||
|
||||
unsigned long crc32_buf(const char *buffer, unsigned int len) {
|
||||
int i, j;
|
||||
unsigned long crc, c;
|
||||
const char *p;
|
||||
|
||||
if (!crc32_is_initialized) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
c = (unsigned long) i;
|
||||
for (j = 0; j < 8; j++)
|
||||
c = c & 1 ? CRC32_POLY ^ (c >> 1) : c >> 1;
|
||||
crc32_table[i] = c;
|
||||
}
|
||||
crc32_is_initialized = 1;
|
||||
}
|
||||
|
||||
crc = 0xffffffff;
|
||||
for (p = buffer; len > 0; ++p, --len)
|
||||
crc = (crc >> 8) ^ crc32_table[(crc ^ *p) & 0xff];
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
void rawnet_hexdump(const void *what, int count) {
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
char buffer1[16 * 3 + 1];
|
||||
char buffer2[16 + 1];
|
||||
unsigned offset;
|
||||
unsigned char *cp = (unsigned char *)what;
|
||||
|
||||
|
||||
offset = 0;
|
||||
while (count > 0) {
|
||||
unsigned char x = *cp++;
|
||||
|
||||
buffer1[offset * 3] = hex[x >> 4];
|
||||
buffer1[offset * 3 + 1] = hex[x & 0x0f];
|
||||
buffer1[offset * 3 + 2] = ' ';
|
||||
|
||||
buffer2[offset] = (x < 0x80) && isprint(x) ? x : '.';
|
||||
|
||||
|
||||
--count;
|
||||
++offset;
|
||||
if (offset == 16 || count == 0) {
|
||||
buffer1[offset * 3] = 0;
|
||||
buffer2[offset] = 0;
|
||||
fprintf(stderr, "%-50s %s\n", buffer1, buffer2);
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum {
|
||||
eth_dest = 0, // destination address
|
||||
eth_src = 6, // source address
|
||||
eth_type = 12, // packet type
|
||||
eth_data = 14, // packet data
|
||||
};
|
||||
|
||||
enum {
|
||||
ip_ver_ihl = 0,
|
||||
ip_tos = 1,
|
||||
ip_len = 2,
|
||||
ip_id = 4,
|
||||
ip_frag = 6,
|
||||
ip_ttl = 8,
|
||||
ip_proto = 9,
|
||||
ip_header_cksum = 10,
|
||||
ip_src = 12,
|
||||
ip_dest = 16,
|
||||
ip_data = 20,
|
||||
};
|
||||
|
||||
enum {
|
||||
udp_source = 0, // source port
|
||||
udp_dest = 2, // destination port
|
||||
udp_len = 4, // length
|
||||
udp_cksum = 6, // checksum
|
||||
udp_data = 8, // total length udp header
|
||||
};
|
||||
|
||||
enum {
|
||||
bootp_op = 0, // operation
|
||||
bootp_hw = 1, // hardware type
|
||||
bootp_hlen = 2, // hardware len
|
||||
bootp_hp = 3, // hops
|
||||
bootp_transid = 4, // transaction id
|
||||
bootp_secs = 8, // seconds since start
|
||||
bootp_flags = 10, // flags
|
||||
bootp_ipaddr = 12, // ip address knwon by client
|
||||
bootp_ipclient = 16, // client ip from server
|
||||
bootp_ipserver = 20, // server ip
|
||||
bootp_ipgateway = 24, // gateway ip
|
||||
bootp_client_hrd = 28, // client mac address
|
||||
bootp_spare = 34,
|
||||
bootp_host = 44,
|
||||
bootp_fname = 108,
|
||||
bootp_data = 236, // total length bootp packet
|
||||
};
|
||||
|
||||
enum {
|
||||
arp_hw = 14, // hw type (eth = 0001)
|
||||
arp_proto = 16, // protocol (ip = 0800)
|
||||
arp_hwlen = 18, // hw addr len (eth = 06)
|
||||
arp_protolen = 19, // proto addr len (ip = 04)
|
||||
arp_op = 20, // request = 0001, reply = 0002
|
||||
arp_shw = 22, // sender hw addr
|
||||
arp_sp = 28, // sender proto addr
|
||||
arp_thw = 32, // target hw addr
|
||||
arp_tp = 38, // target protoaddr
|
||||
arp_data = 42, // total length of packet
|
||||
};
|
||||
|
||||
enum {
|
||||
dhcp_discover = 1,
|
||||
dhcp_offer = 2,
|
||||
dhcp_request = 3,
|
||||
dhcp_decline = 4,
|
||||
dhcp_pack = 5,
|
||||
dhcp_nack = 6,
|
||||
dhcp_release = 7,
|
||||
dhcp_inform = 8,
|
||||
};
|
||||
|
||||
static uint8_t oo[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
static uint8_t ff[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
static int is_arp(const uint8_t *packet, unsigned size) {
|
||||
return size == arp_data
|
||||
&& packet[12] == 0x08 && packet[13] == 0x06 /* ARP */
|
||||
&& packet[14] == 0x00 && packet[15] == 0x01 /* ethernet */
|
||||
&& packet[16] == 0x08 && packet[17] == 0x00 /* ipv4 */
|
||||
&& packet[18] == 0x06 /* hardware size */
|
||||
&& packet[19] == 0x04 /* protocol size */
|
||||
;
|
||||
}
|
||||
|
||||
static int is_broadcast(const uint8_t *packet, unsigned size) {
|
||||
return !memcmp(packet + 0, ff, 6);
|
||||
}
|
||||
|
||||
static int is_unicast(const uint8_t *packet, unsigned size) {
|
||||
return (*packet & 0x01) == 0;
|
||||
}
|
||||
|
||||
static int is_multicast(const uint8_t *packet, unsigned size) {
|
||||
return (*packet & 0x01) == 0x01 && !is_broadcast(packet, size);
|
||||
}
|
||||
|
||||
static int is_dhcp_out(const uint8_t *packet, unsigned size) {
|
||||
static uint8_t cookie[] = { 0x63, 0x82, 0x53, 0x63 };
|
||||
return size >= 282
|
||||
//&& !memcmp(&packet[0], ff, 6) /* broadcast */
|
||||
&& packet[12] == 0x08 && packet[13] == 0x00
|
||||
&& packet[14] == 0x45 /* version 4 */
|
||||
&& packet[23] == 0x11 /* UDP */
|
||||
//&& !memcmp(&packet[26], oo, 4) /* source ip */
|
||||
//&& !memcmp(&packet[30], ff, 4) /* dest ip */
|
||||
&& packet[34] == 0x00 && packet[35] == 0x44 /* source port */
|
||||
&& packet[36] == 0x00 && packet[37] == 0x43 /* dest port */
|
||||
//&& packet[44] == 0x01 /* dhcp boot req */
|
||||
&& packet[43] == 0x01 /* ethernet */
|
||||
&& packet[44] == 0x06 /* 6 byte mac */
|
||||
&& !memcmp(&packet[278], cookie, 4)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
static int is_dhcp_in(const uint8_t *packet, unsigned size) {
|
||||
static uint8_t cookie[] = { 0x63, 0x82, 0x53, 0x63 };
|
||||
return size >= 282
|
||||
//&& !memcmp(&packet[0], ff, 6) /* broadcast */
|
||||
&& packet[12] == 0x08 && packet[13] == 0x00
|
||||
&& packet[14] == 0x45 /* version 4 */
|
||||
&& packet[23] == 0x11 /* UDP */
|
||||
//&& !memcmp(&packet[26], oo, 4) /* source ip */
|
||||
//&& !memcmp(&packet[30], ff, 4) /* dest ip */
|
||||
&& packet[34] == 0x00 && packet[35] == 0x43 /* source port */
|
||||
&& packet[36] == 0x00 && packet[37] == 0x44 /* dest port */
|
||||
//&& packet[44] == 0x01 /* dhcp boot req */
|
||||
&& packet[43] == 0x01 /* ethernet */
|
||||
&& packet[44] == 0x06 /* 6 byte mac */
|
||||
&& !memcmp(&packet[278], cookie, 4)
|
||||
;
|
||||
}
|
||||
|
||||
static unsigned ip_checksum(const uint8_t *packet) {
|
||||
unsigned x = 0;
|
||||
unsigned i;
|
||||
for (i = 0; i < ip_data; i += 2) {
|
||||
if (i == ip_header_cksum) continue;
|
||||
x += packet[eth_data + i + 0 ] << 8;
|
||||
x += packet[eth_data + i + 1];
|
||||
}
|
||||
|
||||
/* add the carry */
|
||||
x += x >> 16;
|
||||
x &= 0xffff;
|
||||
return ~x & 0xffff;
|
||||
}
|
||||
|
||||
void rawnet_fix_incoming_packet(uint8_t *packet, unsigned size, const uint8_t real_mac[6], const uint8_t fake_mac[6]) {
|
||||
|
||||
if (memcmp(packet + 0, real_mac, 6) == 0)
|
||||
memcpy(packet + 0, fake_mac, 6);
|
||||
|
||||
/* dhcp request - fix the hardware address */
|
||||
if (is_unicast(packet, size) && is_dhcp_in(packet, size)) {
|
||||
if (!memcmp(packet + 70, real_mac, 6))
|
||||
memcpy(packet + 70, fake_mac, 6);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void rawnet_fix_outgoing_packet(uint8_t *packet, unsigned size, const uint8_t real_mac[6], const uint8_t fake_mac[6]) {
|
||||
|
||||
|
||||
|
||||
if (memcmp(packet + 6, fake_mac, 6) == 0)
|
||||
memcpy(packet + 6, real_mac, 6);
|
||||
|
||||
if (is_arp(packet, size)) {
|
||||
/* sender mac address */
|
||||
if (!memcmp(packet + 22, fake_mac, 6))
|
||||
memcpy(packet + 22, real_mac, 6);
|
||||
return;
|
||||
}
|
||||
|
||||
/* dhcp request - fix the hardware address */
|
||||
if (is_broadcast(packet, size) && is_dhcp_out(packet, size)) {
|
||||
|
||||
if (!memcmp(packet + 70, fake_mac, 6))
|
||||
memcpy(packet + 70, real_mac, 6);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
62
src/rawnet/rawnetsupp.h
Normal file
62
src/rawnet/rawnetsupp.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* This file is a consolidation of functions required for tfe
|
||||
* emulation taken from the following files
|
||||
*
|
||||
* lib.h - Library functions.
|
||||
* util.h - Miscellaneous utility functions.
|
||||
* crc32.h
|
||||
*
|
||||
* Written by
|
||||
* Andreas Boose <viceteam@t-online.de>
|
||||
* Ettore Perazzoli <ettore@comm2000.it>
|
||||
* Manfred Spraul <manfreds@colorfullife.com>
|
||||
* Andreas Matthies <andreas.matthies@gmx.net>
|
||||
* Tibor Biczo <crown@mail.matav.hu>
|
||||
* Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>*
|
||||
*
|
||||
* This file is part of VICE, the Versatile Commodore Emulator.
|
||||
* See README for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef _TFESUPP_H
|
||||
#define _TFESUPP_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern FILE* g_fh; // Filehandle for log file
|
||||
|
||||
extern void *lib_malloc(size_t size);
|
||||
extern void *lib_realloc(void *p, size_t size);
|
||||
extern void lib_free(void *ptr);
|
||||
extern char *lib_stralloc(const char *str);
|
||||
|
||||
extern int util_string_set(char **str, const char *new_value);
|
||||
|
||||
extern unsigned long crc32_buf(const char *buffer, unsigned int len);
|
||||
|
||||
extern void rawnet_hexdump(const void *what, int count);
|
||||
extern void rawnet_fix_incoming_packet(uint8_t *packet, unsigned size, const uint8_t real_mac[6], const uint8_t fake_mac[6]);
|
||||
extern void rawnet_fix_outgoing_packet(uint8_t *packet, unsigned size, const uint8_t real_mac[6], const uint8_t fake_mac[6]);
|
||||
|
||||
|
||||
#define log_message(level,...) do { fprintf(stderr,__VA_ARGS__); fputs("\n", stderr); } while (0)
|
||||
#endif
|
331
src/rawnet/vmnet_helper.c
Normal file
331
src/rawnet/vmnet_helper.c
Normal file
|
@ -0,0 +1,331 @@
|
|||
/* vmnet helper */
|
||||
/* because it needs root permissions ... sigh */
|
||||
|
||||
/*
|
||||
* basicly... run as root, read messages from stdin, write to stdout.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <vmnet/vmnet.h>
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
|
||||
|
||||
static interface_ref interface;
|
||||
static uint8_t interface_mac[6];
|
||||
static long interface_mtu;
|
||||
static long interface_packet_size;
|
||||
static vmnet_return_t interface_status;
|
||||
|
||||
static size_t buffer_size = 0;
|
||||
static uint8_t *buffer = NULL;
|
||||
|
||||
enum {
|
||||
MSG_QUIT,
|
||||
MSG_STATUS,
|
||||
MSG_READ,
|
||||
MSG_WRITE
|
||||
};
|
||||
#define MAKE_MSG(msg, extra) (msg | ((extra) << 8))
|
||||
|
||||
ssize_t safe_read(void *buffer, size_t nbyte) {
|
||||
|
||||
ssize_t rv;
|
||||
for(;;) {
|
||||
rv = read(STDIN_FILENO, buffer, nbyte);
|
||||
if (rv < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
err(1, "read");
|
||||
}
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
ssize_t safe_readv(const struct iovec *iov, int iovcnt) {
|
||||
|
||||
ssize_t rv;
|
||||
for(;;) {
|
||||
rv = readv(STDIN_FILENO, iov, iovcnt);
|
||||
if (rv < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
err(1, "readv");
|
||||
}
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
ssize_t safe_write(const void *buffer, size_t nbyte) {
|
||||
|
||||
ssize_t rv;
|
||||
for(;;) {
|
||||
rv = write(STDOUT_FILENO, buffer, nbyte);
|
||||
if (rv < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
err(1, "write");
|
||||
}
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
ssize_t safe_writev(const struct iovec *iov, int iovcnt) {
|
||||
|
||||
ssize_t rv;
|
||||
for(;;) {
|
||||
rv = writev(STDOUT_FILENO, iov, iovcnt);
|
||||
if (rv < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
err(1, "writev");
|
||||
}
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
void msg_status(uint32_t size) {
|
||||
struct iovec iov[4];
|
||||
|
||||
uint32_t msg = MAKE_MSG(MSG_STATUS, 6 + 4 + 4);
|
||||
|
||||
iov[0].iov_len = 4;
|
||||
iov[0].iov_base = &msg;
|
||||
|
||||
iov[1].iov_len = 6;
|
||||
iov[1].iov_base = interface_mac;
|
||||
|
||||
iov[2].iov_len = 4;
|
||||
iov[2].iov_base = &interface_mtu;
|
||||
|
||||
iov[3].iov_len = 4;
|
||||
iov[3].iov_base = &interface_packet_size;
|
||||
|
||||
|
||||
safe_writev(iov, 4);
|
||||
}
|
||||
|
||||
int classify_mac(uint8_t *mac) {
|
||||
if ((mac[0] & 0x01) == 0) return 1; /* unicast */
|
||||
if (memcmp(mac, "\xff\xff\xff\xff\xff\xff", 6) == 0) return 0xff; /* broadcast */
|
||||
return 2; /* multicast */
|
||||
}
|
||||
|
||||
void msg_read(uint32_t flags) {
|
||||
/* flag to block broadcast, multicast, etc? */
|
||||
|
||||
int count = 1;
|
||||
int xfer;
|
||||
vmnet_return_t st;
|
||||
struct vmpktdesc v;
|
||||
struct iovec iov[2];
|
||||
|
||||
uint32_t msg;
|
||||
|
||||
|
||||
for(;;) {
|
||||
int type;
|
||||
|
||||
iov[0].iov_base = buffer;
|
||||
iov[0].iov_len = interface_packet_size;
|
||||
|
||||
v.vm_pkt_size = interface_packet_size;
|
||||
v.vm_pkt_iov = iov;
|
||||
v.vm_pkt_iovcnt = 1;
|
||||
v.vm_flags = 0;
|
||||
|
||||
count = 1;
|
||||
st = vmnet_read(interface, &v, &count);
|
||||
if (st != VMNET_SUCCESS) errx(1, "vmnet_read");
|
||||
|
||||
if (count < 1) break;
|
||||
/* todo -- skip multicast messages based on flag? */
|
||||
type = classify_mac(buffer);
|
||||
if (type == 2) continue; /* multicast */
|
||||
break;
|
||||
}
|
||||
|
||||
xfer = count == 1 ? v.vm_pkt_size : 0;
|
||||
msg = MAKE_MSG(MSG_READ, xfer);
|
||||
iov[0].iov_len = 4;
|
||||
iov[0].iov_base = &msg;
|
||||
iov[1].iov_len = xfer;
|
||||
iov[1].iov_base = buffer;
|
||||
|
||||
safe_writev(iov, count == 1 ? 2 : 1);
|
||||
}
|
||||
|
||||
|
||||
void msg_write(uint32_t size) {
|
||||
|
||||
ssize_t ok;
|
||||
|
||||
int count = 1;
|
||||
vmnet_return_t st;
|
||||
struct vmpktdesc v;
|
||||
struct iovec iov;
|
||||
uint32_t msg;
|
||||
|
||||
if (size > interface_packet_size) errx(1, "packet too big");
|
||||
for(;;) {
|
||||
ok = safe_read(buffer, size);
|
||||
if (ok < 0) err(1,"read");
|
||||
if (ok != size) errx(1,"message truncated");
|
||||
break;
|
||||
}
|
||||
|
||||
iov.iov_base = buffer;
|
||||
iov.iov_len = size;
|
||||
|
||||
v.vm_pkt_size = size;
|
||||
v.vm_pkt_iov = &iov;
|
||||
v.vm_pkt_iovcnt = 1;
|
||||
v.vm_flags = 0;
|
||||
|
||||
st = vmnet_write(interface, &v, &count);
|
||||
|
||||
if (st != VMNET_SUCCESS) errx(1, "vmnet_write");
|
||||
|
||||
|
||||
msg = MAKE_MSG(MSG_WRITE, size);
|
||||
iov.iov_len = 4;
|
||||
iov.iov_base = &msg;
|
||||
|
||||
safe_writev(&iov, 1);
|
||||
}
|
||||
|
||||
void startup(void) {
|
||||
|
||||
xpc_object_t dict;
|
||||
dispatch_queue_t q;
|
||||
dispatch_semaphore_t sem;
|
||||
|
||||
|
||||
memset(interface_mac, 0, sizeof(interface_mac));
|
||||
interface_status = 0;
|
||||
interface_mtu = 0;
|
||||
interface_packet_size = 0;
|
||||
|
||||
dict = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_uint64(dict, vmnet_operation_mode_key, VMNET_SHARED_MODE);
|
||||
sem = dispatch_semaphore_create(0);
|
||||
q = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
|
||||
|
||||
interface = vmnet_start_interface(dict, q, ^(vmnet_return_t status, xpc_object_t params){
|
||||
interface_status = status;
|
||||
if (status == VMNET_SUCCESS) {
|
||||
const char *cp;
|
||||
cp = xpc_dictionary_get_string(params, vmnet_mac_address_key);
|
||||
fprintf(stderr, "vmnet mac: %s\n", cp);
|
||||
sscanf(cp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
||||
&interface_mac[0],
|
||||
&interface_mac[1],
|
||||
&interface_mac[2],
|
||||
&interface_mac[3],
|
||||
&interface_mac[4],
|
||||
&interface_mac[5]
|
||||
);
|
||||
|
||||
interface_mtu = xpc_dictionary_get_uint64(params, vmnet_mtu_key);
|
||||
interface_packet_size = xpc_dictionary_get_uint64(params, vmnet_max_packet_size_key);
|
||||
|
||||
fprintf(stderr, "vmnet mtu: %u\n", (unsigned)interface_mtu);
|
||||
fprintf(stderr, "vmnet packet size: %u\n", (unsigned)interface_packet_size);
|
||||
|
||||
}
|
||||
dispatch_semaphore_signal(sem);
|
||||
});
|
||||
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
if (interface_status == VMNET_SUCCESS) {
|
||||
buffer_size = (interface_packet_size * 2 + 1023) & ~1023;
|
||||
buffer = (uint8_t *)malloc(buffer_size);
|
||||
} else {
|
||||
if (interface) {
|
||||
vmnet_stop_interface(interface, q, ^(vmnet_return_t status){
|
||||
dispatch_semaphore_signal(sem);
|
||||
});
|
||||
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
|
||||
interface = NULL;
|
||||
}
|
||||
errx(1,"vmnet_start_interface failed");
|
||||
}
|
||||
|
||||
|
||||
dispatch_release(sem);
|
||||
xpc_release(dict);
|
||||
|
||||
}
|
||||
|
||||
void shutdown(void) {
|
||||
|
||||
dispatch_queue_t q;
|
||||
dispatch_semaphore_t sem;
|
||||
|
||||
|
||||
if (interface) {
|
||||
sem = dispatch_semaphore_create(0);
|
||||
q = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
|
||||
|
||||
vmnet_stop_interface(interface, q, ^(vmnet_return_t status){
|
||||
dispatch_semaphore_signal(sem);
|
||||
});
|
||||
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
|
||||
dispatch_release(sem);
|
||||
|
||||
interface = NULL;
|
||||
interface_status = 0;
|
||||
}
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
buffer_size = 0;
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
|
||||
uint32_t msg;
|
||||
uint32_t extra;
|
||||
ssize_t ok;
|
||||
|
||||
|
||||
startup();
|
||||
|
||||
for(;;) {
|
||||
ok = safe_read(&msg, 4);
|
||||
if (ok == 0) break;
|
||||
if (ok != 4) errx(1,"read msg");
|
||||
|
||||
extra = msg >> 8;
|
||||
msg = msg & 0xff;
|
||||
|
||||
switch(msg) {
|
||||
case MSG_STATUS:
|
||||
msg_status(extra);
|
||||
break;
|
||||
case MSG_QUIT:
|
||||
shutdown();
|
||||
exit(0);
|
||||
case MSG_READ:
|
||||
msg_read(extra);
|
||||
break;
|
||||
case MSG_WRITE:
|
||||
msg_write(extra);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
shutdown();
|
||||
exit(0);
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
#include "debug.h"
|
||||
#include "glog.h"
|
||||
#include "options.h"
|
||||
#include "version.h"
|
||||
|
||||
extern const char *g_config_gsplus_name_list[];
|
||||
extern char g_config_gsplus_screenshot_dir[];
|
||||
|
@ -168,7 +169,7 @@ int g_imagewriter_paper = 0;
|
|||
int g_imagewriter_banner = 0;
|
||||
|
||||
int g_config_iwm_vbl_count = 0;
|
||||
const char g_gsplus_version_str[] = "0.14";
|
||||
const char g_gsplus_version_str[] = GSPLUS_VERSION_STRING;
|
||||
int g_pause=0; // OG Added pause
|
||||
|
||||
#define START_DCYCS (0.0)
|
||||
|
|
33
src/string_extra.c
Normal file
33
src/string_extra.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "string_extra.h"
|
||||
|
||||
/* from MUSL/MIT */
|
||||
|
||||
#ifndef HAVE_STRCASESTR
|
||||
char *strcasestr(const char *h, const char *n)
|
||||
{
|
||||
size_t l = strlen(n);
|
||||
for (; *h; h++) if (!strncasecmp(h, n, l)) return (char *)h;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRCASECMP
|
||||
int strcasecmp(const char *l, const char *r)
|
||||
{
|
||||
for (; *l && *r && (*l == *r || tolower(*l) == tolower(*r)); l++, r++);
|
||||
return tolower(*l) - tolower(*r);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRNCASECMP
|
||||
|
||||
int strncasecmp(const char *l, const char *r, size_t n)
|
||||
{
|
||||
if (!n--) return 0;
|
||||
for (; *l && *r && n && (*l == *r || tolower(*l) == tolower(*r)); l++, r++, n--);
|
||||
return tolower(*l) - tolower(*r);
|
||||
}
|
||||
#endif
|
20
src/string_extra.h.in
Normal file
20
src/string_extra.h.in
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef STRING_EXTRA_H
|
||||
#define STRING_EXTRA_H
|
||||
|
||||
#cmakedefine HAVE_STRCASECMP
|
||||
#cmakedefine HAVE_STRNCASECMP
|
||||
#cmakedefine HAVE_STRCASESTR
|
||||
|
||||
#ifndef HAVE_STRCASECMP
|
||||
extern int strcasecmp(const char *, const char *);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRNCASESTR
|
||||
extern int strncasecmp(const char *, const char *, size_t);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRCASESTR
|
||||
extern char *strcasestr(const char *, const char *);
|
||||
#endif
|
||||
|
||||
#endif
|
1
src/version.h.in
Normal file
1
src/version.h.in
Normal file
|
@ -0,0 +1 @@
|
|||
#define GSPLUS_VERSION_STRING "@gsplus_VERSION_MAJOR@.@gsplus_VERSION_MINOR@"
|
Loading…
Reference in New Issue
Block a user