vice cleaned up TFE and called it RAWNET.  Slightly better code separation.
I removed libnet stuff in the unix version and added a darwin version that uses the vmnet framework.
This commit is contained in:
Kelvin Sherlock 2018-12-13 23:20:04 -05:00
parent e37e50affe
commit 698678f508
12 changed files with 3517 additions and 0 deletions

View File

@ -95,6 +95,7 @@ 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)

13
src/rawnet/CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
if (WIN32)
set(rawnetarch rawnetarch_win32.c)
elseif(APPLE)
set(rawnetarch rawnetarch_darwin.c)
elseif(UNIX)
set(rawnetarch rawnetarch_unix.c)
endif()
add_library(rawnet cs8900.c rawnet.c rawnetsupp.c ${rawnetarch})
target_compile_definitions(rawnet PUBLIC HAVE_RAWNET)

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

79
src/rawnet/rawnet.c Normal file
View File

@ -0,0 +1,79 @@
/*
* 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();
}
#endif /* #ifdef HAVE_RAWNET */

75
src/rawnet/rawnet.h Normal file
View File

@ -0,0 +1,75 @@
/*
* 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);
#endif

68
src/rawnet/rawnetarch.h Normal file
View File

@ -0,0 +1,68 @@
/*
* 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);
#endif

View File

@ -0,0 +1,255 @@
/*
* 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 const uint8_t broadcast_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static interface_ref interface;
static uint8_t interface_mac[6];
static uint64_t interface_mtu;
static uint64_t interface_packet_size;
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.
*/
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);
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);
}
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
if (interface_status != VMNET_SUCCESS) {
log_message(rawnet_arch_log, "vmnet_start_interface failed\n");
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;
}
}
void rawnet_arch_set_mac(const uint8_t mac[6]) {
/* NOP */
}
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 */
}
void rawnet_arch_transmit(int force, int onecoll, int inhibit_crc, int tx_pad_dis, int txlength, uint8_t *txframe) {
int count = 1;
vmnet_return_t st;
struct vmpktdesc v;
struct iovec iov;
if (txlength == 0) return;
if (txlength > interface_packet_size) {
log_message(rawnet_arch_log, "packet is too big: %d\n", txlength);
return;
}
iov.iov_base = txframe;
iov.iov_len = txlength;
v.vm_pkt_size = txlength;
v.vm_pkt_iov = &iov;
v.vm_pkt_iovcnt = 1;
v.vm_flags = 0;
st = vmnet_write(interface, &v, &count);
if (st != VMNET_SUCCESS) {
log_message(rawnet_arch_log, "vmnet_write failed!\n");
}
return;
}
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) {
char *buffer;
//unsigned hashreg;
int count = 1;
int xfer;
vmnet_return_t st;
struct vmpktdesc v;
struct iovec iov;
buffer = malloc(interface_packet_size);
iov.iov_base = 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_write failed!\n");
free(buffer);
return 0;
}
if (count == 0) {
free(buffer);
return 0;
}
xfer = iov.iov_len;
if (xfer > *plen) xfer = *plen;
memcpy(pbuffer, buffer, xfer);
xfer = iov.iov_len;
if (xfer & 0x01) ++xfer; /* ??? */
*plen = xfer; /* actual frame size */
*phashed =
*phash_index =
*pbroadcast =
*pcorrect_mac =
*pcrc_error = 0;
*prx_ok = 1;
*pcorrect_mac = memcmp(buffer, interface_mac, 6) == 0;
*pbroadcast = memcmp(buffer, broadcast_mac, 6) == 0;
/* vmnet won't send promiscuous packets */
#if 0
hashreg = (~crc32_buf(buffer, 6) >> 26) & 0x3f;
if (hash_mask[hashreg >= 32] & (1 << (hashreg & 0x1F))) {
*phashed = 1;
*phash_index = hashreg;
} else {
*phashed = 0;
*phash_index = 0;
}
#endif
free(buffer);
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");
}

View File

@ -0,0 +1,538 @@
/** \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"
/*
* 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;
/** \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.");
return 0;
}
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;
}
/** \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)
{
#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
#ifdef RAWNET_DEBUG_PKTDUMP
debug_output("Transmit frame: ", txframe, txlength);
#endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
if (pcap_sendpacket(rawnet_pcap_fp, txframe, txlength) < 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 len;
rawnet_pcap_internal_t internal = { *plen, pbuffer };
#ifdef RAWNET_DEBUG_ARCH
log_message(rawnet_arch_log,
"rawnet_arch_receive() called, with *plen=%u.",
*plen);
#endif
assert((*plen & 1) == 0);
len = rawnet_arch_receive_frame(&internal);
if (len != -1) {
#ifdef RAWNET_DEBUG_PKTDUMP
debug_output("Received frame: ", internal.buffer, internal.len);
#endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
if (len & 1) {
++len;
}
*plen = len;
/* we don't decide if this frame fits the needs;
* by setting all zero, we let tfe.c do the work
* for us
*/
*phashed =
*phash_index =
*pbroadcast =
*pcorrect_mac =
*pcrc_error = 0;
/* this frame has been received correctly */
*prx_ok = 1;
return 1;
}
return 0;
}
/** \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;
}
#endif /* #ifdef HAVE_RAWNET */

View File

@ -0,0 +1,542 @@
/** \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>
#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 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 *);
/** #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_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 HINSTANCE pcap_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 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;
p_pcap_open_live = 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;
}
}
/* since I don't like typing too much... */
#define GET_PROC_ADDRESS_AND_TEST( _name_ ) \
p_##_name_ = (_name_##_t) GetProcAddress(pcap_library, #_name_); \
if (!p_##_name_ ) { \
log_message(rawnet_arch_log, "GetProcAddress " #_name_ " failed!"); \
EthernetPcapFreeLibrary(); \
return FALSE; \
}
static BOOL EthernetPcapLoadLibrary(void)
{
if (!pcap_library) {
pcap_library = LoadLibrary(TEXT("wpcap.dll"));
if (!pcap_library) {
log_message(rawnet_arch_log, "LoadLibrary WPCAP.DLL failed!");
return FALSE;
}
GET_PROC_ADDRESS_AND_TEST(pcap_open_live);
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);
}
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);
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;
}
if ((*p_pcap_setnonblock)(EthernetPcapFP, 1, EthernetPcapErrbuf) < 0) {
log_message(rawnet_arch_log, "WARNING: Setting PCAP to non-blocking failed: '%s'", EthernetPcapErrbuf);
}
/* 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();
return FALSE;
}
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 force - FORCE: Delete waiting frames in transmit buffer */
/* int onecoll - ONECOLL: Terminate after just one collision */
/* int inhibit_crc - INHIBITCRC: Do not append CRC to the transmission */
/* int tx_pad_dis - TXPADDIS: Disable padding to 60 Bytes */
/* int txlength - Frame length */
/* uint8_t *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)
{
#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
#ifdef RAWNET_DEBUG_PKTDUMP
debug_output("Transmit frame: ", txframe, txlength);
#endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
if ((*p_pcap_sendpacket)(EthernetPcapFP, txframe, txlength) == -1) {
log_message(rawnet_arch_log, "WARNING! Could not send packet!");
}
}
/*
rawnet_arch_receive()
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 *plen byte are transferred into the buffer given by pbuffer
- *plen gets the length of the received frame, EVEN if this is more
than has been copied to pbuffer!
- if the dest. address was accepted by the hash filter, *phashed is set, else
cleared.
- if the dest. address was accepted by the hash filter, *phash_index is
set to the number of the rule leading to the acceptance
- if the receive was ok (good CRC and valid length), *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()), *pcorrect_mac is set, else cleared.
- if the dest. address was accepted since it was a broadcast address,
*pbroadcast is set, else cleared.
- if the received frame had a crc error, *pcrc_error is set, else cleared
*/
/* uint8_t *pbuffer - where to store a frame */
/* int *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 */
/* int *phashed - set if the dest. address is accepted by the hash filter */
/* int *phash_index - hash table index if hashed == TRUE */
/* int *prx_ok - set if good CRC and valid length */
/* int *pcorrect_mac - set if dest. address is exactly our IA */
/* int *pbroadcast - set if dest. address is a broadcast address */
/* int *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 len;
Ethernet_PCAP_internal_t internal;
internal.len = *plen;
internal.buffer = pbuffer;
#ifdef RAWNET_DEBUG_ARCH
log_message(rawnet_arch_log, "rawnet_arch_receive() called, with *plen=%u.", *plen);
#endif
assert((*plen & 1) == 0);
len = rawnet_arch_receive_frame(&internal);
if (len != -1) {
#ifdef RAWNET_DEBUG_PKTDUMP
debug_output("Received frame: ", internal.buffer, internal.len);
#endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
if (len & 1) {
++len;
}
*plen = len;
/* we don't decide if this frame fits the needs;
* by setting all zero, we let ethernet.c do the work
* for us
*/
*phashed = *phash_index = *pbroadcast = *pcorrect_mac = *pcrc_error = 0;
/* this frame has been received correctly */
*prx_ok = 1;
return 1;
}
return 0;
}
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;
}
#endif /* #ifdef HAVE_RAWNET */

151
src/rawnet/rawnetsupp.c Normal file
View File

@ -0,0 +1,151 @@
/*
* 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;
}

56
src/rawnet/rawnetsupp.h Normal file
View File

@ -0,0 +1,56 @@
/*
* 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>
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);
#define log_message(level,...) fprintf(stderr,__VA_ARGS__)
#endif