mirror of
https://github.com/digarok/gsplus.git
synced 2024-06-01 08:41:36 +00:00
rawnet
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:
parent
e37e50affe
commit
698678f508
|
@ -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
13
src/rawnet/CMakeLists.txt
Normal 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
1675
src/rawnet/cs8900.c
Normal file
File diff suppressed because it is too large
Load Diff
64
src/rawnet/cs8900.h
Normal file
64
src/rawnet/cs8900.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* cs8900.h - CS8900 Ethernet Core
|
||||
*
|
||||
* Written by
|
||||
* Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
|
||||
*
|
||||
* This file is part of VICE, the Versatile Commodore Emulator.
|
||||
* See README for copyright notice.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef HAVE_RAWNET
|
||||
#error CS8900.H should not be included if HAVE_RAWNET is not defined!
|
||||
#endif /* #ifdef HAVE_RAWNET */
|
||||
|
||||
#ifndef VICE_CS8900_H
|
||||
#define VICE_CS8900_H
|
||||
|
||||
//#include <"types.h">
|
||||
|
||||
typedef struct snapshot_s snapshot_t;
|
||||
extern int cs8900_snapshot_read_module(snapshot_t *s);
|
||||
extern int cs8900_snapshot_write_module(snapshot_t *s);
|
||||
|
||||
extern int cs8900_init(void);
|
||||
extern void cs8900_reset(void);
|
||||
|
||||
extern int cs8900_activate(const char *net_interface);
|
||||
extern int cs8900_deactivate(void);
|
||||
extern void cs8900_shutdown(void);
|
||||
|
||||
extern uint8_t cs8900_read(uint16_t io_address);
|
||||
extern uint8_t cs8900_peek(uint16_t io_address);
|
||||
extern void cs8900_store(uint16_t io_address, uint8_t byte);
|
||||
extern int cs8900_dump(void);
|
||||
|
||||
/*
|
||||
This is a helper for cs8900_receive() to determine if the received frame should be accepted
|
||||
according to the settings.
|
||||
|
||||
This function is even allowed to be called (indirectly via rawnet_should_accept) in rawnetarch.c
|
||||
from rawnet_arch_receive() if necessary, and must be registered using rawnet_set_should_accept_func
|
||||
at init time.
|
||||
*/
|
||||
extern int cs8900_should_accept(unsigned char *buffer, int length, int *phashed, int *phash_index, int *pcorrect_mac, int *pbroadcast, int *pmulticast);
|
||||
|
||||
#endif
|
79
src/rawnet/rawnet.c
Normal file
79
src/rawnet/rawnet.c
Normal 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
75
src/rawnet/rawnet.h
Normal 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
68
src/rawnet/rawnetarch.h
Normal 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
|
255
src/rawnet/rawnetarch_darwin.c
Normal file
255
src/rawnet/rawnetarch_darwin.c
Normal 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");
|
||||
}
|
538
src/rawnet/rawnetarch_unix.c
Normal file
538
src/rawnet/rawnetarch_unix.c
Normal 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 */
|
542
src/rawnet/rawnetarch_win32.c
Normal file
542
src/rawnet/rawnetarch_win32.c
Normal 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
151
src/rawnet/rawnetsupp.c
Normal 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
56
src/rawnet/rawnetsupp.h
Normal 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
|
Loading…
Reference in New Issue
Block a user