basically 0.14 updated with cmake, networking modules, and packaging via github actions - osx/ubuntu

This commit is contained in:
Dagen Brock 2020-02-03 15:43:58 -06:00
parent df0833994a
commit d28578f725
41 changed files with 11112 additions and 135 deletions

143
.github/workflows/release.yml vendored Normal file
View 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
View File

@ -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
View 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)

View File

@ -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

View File

@ -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>

View File

@ -1,5 +1,5 @@
Package: gsplus
Version: 0.14-0
Version: 0.15-0
Section: base
Priority: optional
Architecture: amd64

View File

@ -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

View File

@ -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

View File

@ -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
View 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
View 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

File diff suppressed because it is too large Load Diff

2653
src/assets/NList.Data Normal file

File diff suppressed because it is too large Load Diff

46
src/assets/config.txt Normal file
View 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

View 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()

View File

@ -17,7 +17,7 @@
#include "aarp.h"
#ifdef WIN32
#include <winsock.h>
#include <winsock2.h>
#elif __linux__
#include <netinet/in.h>
#endif

View File

@ -18,7 +18,7 @@
#include "aarp.h"
#ifdef WIN32
#include <winsock.h>
#include <winsock2.h>
#elif __linux__
#include <netinet/in.h>
#endif

View File

@ -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__

View File

@ -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();

View File

@ -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
View 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
View 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

File diff suppressed because it is too large Load Diff

64
src/rawnet/cs8900.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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 */

View 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;
}

View 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;
}

View 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
View 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
View 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
View 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);
}

View File

@ -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
View 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
View 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
View File

@ -0,0 +1 @@
#define GSPLUS_VERSION_STRING "@gsplus_VERSION_MAJOR@.@gsplus_VERSION_MINOR@"