mirror of
https://github.com/solemnwarning/ipxwrapper
synced 2024-12-30 16:45:37 +01:00
Initial implementation of DOSBox encapsulation support.
Incomplete and completely untested at this point, beyond "it compiles".
This commit is contained in:
parent
0bee989d8a
commit
a0234c7459
@ -29,13 +29,20 @@
|
||||
|
||||
#define INTERFACE_CACHE_TTL 5
|
||||
|
||||
BOOL ipx_use_pcap;
|
||||
enum main_config_encap_type ipx_encap_type;
|
||||
|
||||
enum dosbox_state dosbox_state = DOSBOX_DISCONNECTED;
|
||||
|
||||
addr32_t dosbox_local_netnum;
|
||||
addr48_t dosbox_local_nodenum;
|
||||
|
||||
static CRITICAL_SECTION interface_cache_cs;
|
||||
|
||||
static ipx_interface_t *interface_cache = NULL;
|
||||
static time_t interface_cache_ctime = 0;
|
||||
|
||||
static void renew_interface_cache(bool force);
|
||||
|
||||
/* Fetch a list of network interfaces available on the system.
|
||||
*
|
||||
* Returns a linked list of IP_ADAPTER_INFO structures, all allocated within a
|
||||
@ -465,11 +472,12 @@ void ipx_interfaces_init(void)
|
||||
|
||||
log_printf(LOG_INFO, "--");
|
||||
|
||||
if(ipx_use_pcap)
|
||||
if(ipx_encap_type == ENCAP_TYPE_PCAP)
|
||||
{
|
||||
_init_pcap_interfaces();
|
||||
}
|
||||
else{
|
||||
else if(ipx_encap_type == ENCAP_TYPE_IPXWRAPPER)
|
||||
{
|
||||
/* IP interfaces... */
|
||||
|
||||
IP_ADAPTER_INFO *ip_ifaces = load_sys_interfaces(), *ip;
|
||||
@ -559,7 +567,7 @@ void ipx_interfaces_cleanup(void)
|
||||
{
|
||||
DeleteCriticalSection(&interface_cache_cs);
|
||||
|
||||
if(ipx_use_pcap)
|
||||
if(ipx_encap_type == ENCAP_TYPE_PCAP)
|
||||
{
|
||||
for(ipx_interface_t *i = interface_cache; i; i = i->next)
|
||||
{
|
||||
@ -570,12 +578,18 @@ void ipx_interfaces_cleanup(void)
|
||||
free_ipx_interface_list(&interface_cache);
|
||||
}
|
||||
|
||||
/* Flush and repopulate the interface cache. */
|
||||
void ipx_interfaces_reload(void)
|
||||
{
|
||||
renew_interface_cache(true);
|
||||
}
|
||||
|
||||
/* Check the age of the IPX interface cache and reload it if necessary.
|
||||
* Ensure you hold interface_cache_cs before calling.
|
||||
*/
|
||||
static void renew_interface_cache(void)
|
||||
static void renew_interface_cache(bool force)
|
||||
{
|
||||
if(ipx_use_pcap)
|
||||
if(ipx_encap_type == ENCAP_TYPE_PCAP)
|
||||
{
|
||||
/* interface_cache is initialised during init when pcap is in
|
||||
* use and survives for the lifetime of the program.
|
||||
@ -583,11 +597,18 @@ static void renew_interface_cache(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if(time(NULL) - interface_cache_ctime > INTERFACE_CACHE_TTL)
|
||||
if(force || time(NULL) - interface_cache_ctime > INTERFACE_CACHE_TTL)
|
||||
{
|
||||
free_ipx_interface_list(&interface_cache);
|
||||
|
||||
interface_cache = load_ipx_interfaces();
|
||||
if(ipx_encap_type == ENCAP_TYPE_DOSBOX)
|
||||
{
|
||||
interface_cache = load_dosbox_interfaces();
|
||||
}
|
||||
else{
|
||||
interface_cache = load_ipx_interfaces();
|
||||
}
|
||||
|
||||
interface_cache_ctime = time(NULL);
|
||||
}
|
||||
}
|
||||
@ -599,7 +620,7 @@ ipx_interface_t *get_ipx_interfaces(void)
|
||||
{
|
||||
EnterCriticalSection(&interface_cache_cs);
|
||||
|
||||
renew_interface_cache();
|
||||
renew_interface_cache(false);
|
||||
|
||||
ipx_interface_t *copy = copy_ipx_interface_list(interface_cache);
|
||||
|
||||
@ -615,7 +636,7 @@ ipx_interface_t *ipx_interface_by_addr(addr32_t net, addr48_t node)
|
||||
{
|
||||
EnterCriticalSection(&interface_cache_cs);
|
||||
|
||||
renew_interface_cache();
|
||||
renew_interface_cache(false);
|
||||
|
||||
ipx_interface_t *iface;
|
||||
|
||||
@ -640,7 +661,7 @@ ipx_interface_t *ipx_interface_by_subnet(uint32_t ipaddr)
|
||||
{
|
||||
EnterCriticalSection(&interface_cache_cs);
|
||||
|
||||
renew_interface_cache();
|
||||
renew_interface_cache(false);
|
||||
|
||||
ipx_interface_t *iface;
|
||||
|
||||
@ -671,7 +692,7 @@ ipx_interface_t *ipx_interface_by_index(int index)
|
||||
{
|
||||
EnterCriticalSection(&interface_cache_cs);
|
||||
|
||||
renew_interface_cache();
|
||||
renew_interface_cache(false);
|
||||
|
||||
int iface_index = 0;
|
||||
ipx_interface_t *iface;
|
||||
@ -695,7 +716,7 @@ int ipx_interface_count(void)
|
||||
{
|
||||
EnterCriticalSection(&interface_cache_cs);
|
||||
|
||||
renew_interface_cache();
|
||||
renew_interface_cache(false);
|
||||
|
||||
int count = 0;
|
||||
ipx_interface_t *iface;
|
||||
@ -807,3 +828,19 @@ void ipx_free_pcap_interfaces(ipx_pcap_interface_t **interfaces)
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
ipx_interface_t *load_dosbox_interfaces(void)
|
||||
{
|
||||
ipx_interface_t *nics = NULL;
|
||||
|
||||
if(dosbox_state == DOSBOX_CONNECTED)
|
||||
{
|
||||
ipx_interface_t *dosbox_iface = _new_iface(dosbox_local_netnum, dosbox_local_nodenum);
|
||||
if(dosbox_iface)
|
||||
{
|
||||
DL_APPEND(nics, dosbox_iface);
|
||||
}
|
||||
}
|
||||
|
||||
return nics;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* IPXWrapper - Interface header
|
||||
* Copyright (C) 2011 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
* Copyright (C) 2011-2021 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
@ -23,6 +23,7 @@
|
||||
#include <utlist.h>
|
||||
#include <pcap.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -75,7 +76,19 @@ struct ipx_pcap_interface {
|
||||
ipx_pcap_interface_t *next;
|
||||
};
|
||||
|
||||
extern BOOL ipx_use_pcap;
|
||||
extern enum main_config_encap_type ipx_encap_type;
|
||||
|
||||
enum dosbox_state
|
||||
{
|
||||
DOSBOX_DISCONNECTED,
|
||||
DOSBOX_RESOLVING,
|
||||
DOSBOX_REGISTERING,
|
||||
DOSBOX_CONNECTED,
|
||||
};
|
||||
|
||||
extern enum dosbox_state dosbox_state;
|
||||
extern addr32_t dosbox_local_netnum;
|
||||
extern addr48_t dosbox_local_nodenum;
|
||||
|
||||
IP_ADAPTER_INFO *load_sys_interfaces(void);
|
||||
ipx_interface_t *load_ipx_interfaces(void);
|
||||
@ -88,6 +101,7 @@ void free_ipx_interface_list(ipx_interface_t **list);
|
||||
|
||||
void ipx_interfaces_init(void);
|
||||
void ipx_interfaces_cleanup(void);
|
||||
void ipx_interfaces_reload(void);
|
||||
|
||||
ipx_interface_t *get_ipx_interfaces(void);
|
||||
ipx_interface_t *ipx_interface_by_addr(addr32_t net, addr48_t node);
|
||||
@ -98,6 +112,8 @@ int ipx_interface_count(void);
|
||||
ipx_pcap_interface_t *ipx_get_pcap_interfaces(void);
|
||||
void ipx_free_pcap_interfaces(ipx_pcap_interface_t **interfaces);
|
||||
|
||||
ipx_interface_t *load_dosbox_interfaces(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -81,7 +81,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
|
||||
main_config = get_main_config();
|
||||
min_log_level = main_config.log_level;
|
||||
ipx_use_pcap = main_config.encap_type == ENCAP_TYPE_PCAP;
|
||||
ipx_encap_type = main_config.encap_type;
|
||||
|
||||
if(main_config.fw_except)
|
||||
{
|
||||
|
163
src/router.c
163
src/router.c
@ -1,5 +1,5 @@
|
||||
/* IPXWrapper - Router code
|
||||
* Copyright (C) 2011 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
* Copyright (C) 2011-2021 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
@ -38,23 +38,32 @@ static HANDLE router_thread = NULL;
|
||||
/* The shared socket uses the UDP port number specified in the configuration,
|
||||
* every IPXWrapper instance will share it and use it to receive broadcast
|
||||
* packets.
|
||||
*
|
||||
*
|
||||
* The private socket uses a randomly allocated UDP port number and is used to
|
||||
* send packets and receive unicast, it is unique to a single IPXWrapper
|
||||
* instance.
|
||||
*
|
||||
*
|
||||
* When running in WinPcap mode, only the private socket will be opened and it
|
||||
* will be bound to loopback rather than INADDR_ANY since it is only used for
|
||||
* forwarding IPX packets on to local sockets.
|
||||
*
|
||||
* When running in DOSBox mode, only the private socket will be opened and it
|
||||
* will be "connected" to the DOSBox server address.
|
||||
*/
|
||||
|
||||
SOCKET shared_socket = -1;
|
||||
SOCKET private_socket = -1;
|
||||
|
||||
#define DOSBOX_CONNECT_TIMEOUT_SECS 10
|
||||
|
||||
static struct sockaddr_in dosbox_server_addr;
|
||||
static time_t dosbox_connect_begin;
|
||||
|
||||
static void _send_dosbox_registration_request(void);
|
||||
static DWORD router_main(void *arg);
|
||||
|
||||
/* Initialise a UDP socket. */
|
||||
static void _init_socket(SOCKET *sock, uint16_t port, BOOL reuseaddr)
|
||||
static void _init_socket(SOCKET *sock, uint16_t port, BOOL broadcast, BOOL reuseaddr)
|
||||
{
|
||||
/* Socket used for sending and receiving packets on the network. */
|
||||
|
||||
@ -66,8 +75,6 @@ static void _init_socket(SOCKET *sock, uint16_t port, BOOL reuseaddr)
|
||||
|
||||
/* Enable broadcast and address reuse. */
|
||||
|
||||
BOOL broadcast = TRUE;
|
||||
|
||||
setsockopt(*sock, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof(BOOL));
|
||||
setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, (char*)&reuseaddr, sizeof(BOOL));
|
||||
|
||||
@ -110,7 +117,7 @@ void router_init(void)
|
||||
abort();
|
||||
}
|
||||
|
||||
if(ipx_use_pcap)
|
||||
if(ipx_encap_type == ENCAP_TYPE_PCAP)
|
||||
{
|
||||
if((private_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
{
|
||||
@ -129,9 +136,29 @@ void router_init(void)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
else if(ipx_encap_type == ENCAP_TYPE_DOSBOX)
|
||||
{
|
||||
/* TODO: Support DNS. Do this async somewhere within router_main. */
|
||||
|
||||
dosbox_server_addr.sin_family = AF_INET;
|
||||
dosbox_server_addr.sin_addr.s_addr = inet_addr(main_config.dosbox_server_addr);
|
||||
dosbox_server_addr.sin_port = htons(main_config.dosbox_server_port);
|
||||
|
||||
if(connect(private_socket, (struct sockaddr*)(&dosbox_server_addr), sizeof(dosbox_server_addr)) != 0)
|
||||
{
|
||||
log_printf(LOG_ERROR, "Error connecting private socket: %s", w32_error(WSAGetLastError()));
|
||||
abort();
|
||||
}
|
||||
|
||||
_send_dosbox_registration_request();
|
||||
|
||||
dosbox_state = DOSBOX_REGISTERING;
|
||||
|
||||
_init_socket(&private_socket, 0, FALSE, FALSE);
|
||||
}
|
||||
else{
|
||||
_init_socket(&shared_socket, main_config.udp_port, TRUE);
|
||||
_init_socket(&private_socket, 0, FALSE);
|
||||
_init_socket(&shared_socket, main_config.udp_port, TRUE, TRUE);
|
||||
_init_socket(&private_socket, 0, TRUE, FALSE);
|
||||
}
|
||||
|
||||
router_running = true;
|
||||
@ -472,6 +499,68 @@ static void _handle_udp_recv(ipx_packet *packet, size_t packet_size, struct sock
|
||||
data_size);
|
||||
}
|
||||
|
||||
static void _handle_dosbox_registration_response(novell_ipx_packet *packet, size_t packet_size)
|
||||
{
|
||||
if(packet_size < sizeof(novell_ipx_packet)
|
||||
|| ntohs(packet->length) != packet_size
|
||||
|| ntohs(packet->checksum) != 0xFFFF
|
||||
|| ntohs(packet->type) != 2)
|
||||
{
|
||||
/* Doesn't look valid. */
|
||||
log_printf(LOG_ERROR, "Got invalid registration response from DOSBox server!");
|
||||
abort();
|
||||
}
|
||||
|
||||
dosbox_local_netnum = addr32_in(packet->dest_net);
|
||||
dosbox_local_nodenum = addr48_in(packet->dest_node);
|
||||
|
||||
dosbox_state = DOSBOX_CONNECTED;
|
||||
|
||||
ipx_interfaces_reload();
|
||||
|
||||
char local_netnum_s[ADDR32_STRING_SIZE];
|
||||
addr32_string(local_netnum_s, dosbox_local_netnum);
|
||||
|
||||
char local_nodenum_s[ADDR48_STRING_SIZE];
|
||||
addr48_string(local_nodenum_s, dosbox_local_nodenum);
|
||||
|
||||
log_printf(LOG_INFO, "Connected to DOSBox server, local address: %s/%s", local_netnum_s, local_nodenum_s);
|
||||
}
|
||||
|
||||
static void _handle_dosbox_recv(novell_ipx_packet *packet, size_t packet_size)
|
||||
{
|
||||
if(packet_size < sizeof(novell_ipx_packet) || ntohs(packet->length) != packet_size)
|
||||
{
|
||||
/* Doesn't look valid. */
|
||||
log_printf(LOG_ERROR, "Recieved invalid IPX packet from DOSBox server, dropping");
|
||||
return;
|
||||
}
|
||||
|
||||
if(min_log_level <= LOG_DEBUG)
|
||||
{
|
||||
IPX_STRING_ADDR(src_addr, addr32_in(packet->src_net), addr48_in(packet->src_node), packet->src_socket);
|
||||
IPX_STRING_ADDR(dest_addr, addr32_in(packet->dest_net), addr48_in(packet->dest_node), packet->dest_socket);
|
||||
|
||||
log_printf(LOG_DEBUG, "Recieved packet from %s for %s", src_addr, dest_addr);
|
||||
}
|
||||
|
||||
size_t data_size = ntohs(packet->length) - sizeof(novell_ipx_packet);
|
||||
|
||||
_deliver_packet(
|
||||
packet->type,
|
||||
|
||||
addr32_in(packet->src_net),
|
||||
addr48_in(packet->src_node),
|
||||
packet->src_socket,
|
||||
|
||||
addr32_in(packet->dest_net),
|
||||
addr48_in(packet->dest_node),
|
||||
packet->dest_socket,
|
||||
|
||||
packet->data,
|
||||
data_size);
|
||||
}
|
||||
|
||||
static bool _do_udp_recv(int fd)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
@ -489,7 +578,24 @@ static bool _do_udp_recv(int fd)
|
||||
return false;
|
||||
}
|
||||
|
||||
_handle_udp_recv((ipx_packet*)(buf), len, addr);
|
||||
if(ipx_encap_type == ENCAP_TYPE_DOSBOX)
|
||||
{
|
||||
if(dosbox_state == DOSBOX_REGISTERING)
|
||||
{
|
||||
_handle_dosbox_registration_response((novell_ipx_packet*)(buf), len);
|
||||
}
|
||||
else if(dosbox_state == DOSBOX_CONNECTED)
|
||||
{
|
||||
_handle_dosbox_recv((novell_ipx_packet*)(buf), len);
|
||||
}
|
||||
else{
|
||||
/* Unreachable. */
|
||||
abort();
|
||||
}
|
||||
}
|
||||
else{
|
||||
_handle_udp_recv((ipx_packet*)(buf), len, addr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -566,6 +672,29 @@ static void _handle_pcap_frame(u_char *user, const struct pcap_pkthdr *pkt_heade
|
||||
(ntohs(ipx->length) - sizeof(novell_ipx_packet)));
|
||||
}
|
||||
|
||||
static void _send_dosbox_registration_request(void)
|
||||
{
|
||||
novell_ipx_packet reg_pkt;
|
||||
|
||||
reg_pkt.checksum = 0xFFFF;
|
||||
reg_pkt.length = htons(sizeof(novell_ipx_packet));
|
||||
reg_pkt.hops = 0;
|
||||
reg_pkt.type = 2;
|
||||
|
||||
memset(reg_pkt.dest_net, 0, sizeof(reg_pkt.dest_net));
|
||||
memset(reg_pkt.dest_node, 0, sizeof(reg_pkt.dest_node));
|
||||
reg_pkt.dest_socket = 0;
|
||||
|
||||
memset(reg_pkt.src_net, 0, sizeof(reg_pkt.src_net));
|
||||
memset(reg_pkt.src_node, 0, sizeof(reg_pkt.src_node));
|
||||
reg_pkt.src_socket = 0;
|
||||
|
||||
if(send(private_socket, (const void*)(®_pkt), sizeof(reg_pkt), 0) < 0)
|
||||
{
|
||||
log_printf(LOG_ERROR, "Error sending DOSBox IPX registration request: %s", w32_error(WSAGetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD router_main(void *arg)
|
||||
{
|
||||
DWORD exit_status = 0;
|
||||
@ -575,7 +704,7 @@ static DWORD router_main(void *arg)
|
||||
HANDLE *wait_events = &router_event;
|
||||
int n_events = 1;
|
||||
|
||||
if(ipx_use_pcap)
|
||||
if(ipx_encap_type == ENCAP_TYPE_PCAP)
|
||||
{
|
||||
interfaces = get_ipx_interfaces();
|
||||
ipx_interface_t *i;
|
||||
@ -613,7 +742,7 @@ static DWORD router_main(void *arg)
|
||||
break;
|
||||
}
|
||||
|
||||
if(ipx_use_pcap)
|
||||
if(ipx_encap_type == ENCAP_TYPE_PCAP)
|
||||
{
|
||||
ipx_interface_t *i;
|
||||
DL_FOREACH(interfaces, i)
|
||||
@ -628,6 +757,14 @@ static DWORD router_main(void *arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ipx_encap_type == ENCAP_TYPE_DOSBOX)
|
||||
{
|
||||
if(!_do_udp_recv(private_socket))
|
||||
{
|
||||
exit_status = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(!_do_udp_recv(shared_socket) || !_do_udp_recv(private_socket))
|
||||
{
|
||||
@ -637,7 +774,7 @@ static DWORD router_main(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
if(ipx_use_pcap)
|
||||
if(ipx_encap_type == ENCAP_TYPE_PCAP)
|
||||
{
|
||||
free(wait_events);
|
||||
free_ipx_interface_list(&interfaces);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ipxwrapper - Winsock functions
|
||||
* Copyright (C) 2008-2014 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
* Copyright (C) 2008-2021 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
@ -50,7 +50,7 @@ static size_t strsize(void *str, bool unicode)
|
||||
|
||||
static int _max_ipx_payload(void)
|
||||
{
|
||||
if(ipx_use_pcap)
|
||||
if(ipx_encap_type == ENCAP_TYPE_PCAP)
|
||||
{
|
||||
/* TODO: Use real interface MTU */
|
||||
|
||||
@ -66,6 +66,11 @@ static int _max_ipx_payload(void)
|
||||
|
||||
abort();
|
||||
}
|
||||
else if(ipx_encap_type == ENCAP_TYPE_DOSBOX)
|
||||
{
|
||||
// TODO: DOXBox MTU
|
||||
return 1500;
|
||||
}
|
||||
else{
|
||||
return MAX_DATA_SIZE;
|
||||
}
|
||||
@ -331,13 +336,20 @@ SOCKET WSAAPI socket(int af, int type, int protocol)
|
||||
}
|
||||
else if(type == SOCK_STREAM)
|
||||
{
|
||||
if(ipx_use_pcap)
|
||||
if(ipx_encap_type == ENCAP_TYPE_PCAP)
|
||||
{
|
||||
log_printf(LOG_WARNING, "Application attempted to create an SPX socket, this isn't supported when using Ethernet encapsulation");
|
||||
|
||||
WSASetLastError(WSAEPROTONOSUPPORT);
|
||||
return -1;
|
||||
}
|
||||
else if(ipx_encap_type == ENCAP_TYPE_DOSBOX)
|
||||
{
|
||||
log_printf(LOG_WARNING, "Application attempted to create an SPX socket, this isn't supported when using DOSBox encapsulation");
|
||||
|
||||
WSASetLastError(WSAEPROTONOSUPPORT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(protocol != 0 && protocol != NSPROTO_SPX && protocol != NSPROTO_SPXII)
|
||||
{
|
||||
@ -1210,7 +1222,7 @@ static DWORD ipx_send_packet(
|
||||
(unsigned int)(data_size), src_addr, dest_addr);
|
||||
}
|
||||
|
||||
if(ipx_use_pcap)
|
||||
if(ipx_encap_type == ENCAP_TYPE_PCAP)
|
||||
{
|
||||
ipx_interface_t *iface = ipx_interface_by_addr(src_net, src_node);
|
||||
if(iface)
|
||||
@ -1303,6 +1315,53 @@ static DWORD ipx_send_packet(
|
||||
return WSAENETDOWN;
|
||||
}
|
||||
}
|
||||
else if(ipx_encap_type == ENCAP_TYPE_DOSBOX)
|
||||
{
|
||||
if(dosbox_state != DOSBOX_CONNECTED)
|
||||
{
|
||||
return WSAENETDOWN;
|
||||
}
|
||||
else if(src_net != dosbox_local_netnum || src_node != dosbox_local_nodenum)
|
||||
{
|
||||
return WSAENETDOWN;
|
||||
}
|
||||
else{
|
||||
size_t packet_size = sizeof(novell_ipx_packet) + data_size;
|
||||
|
||||
novell_ipx_packet *packet = malloc(packet_size);
|
||||
if(packet == NULL)
|
||||
{
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
packet->checksum = 0xFFFF;
|
||||
packet->length = htons(sizeof(novell_ipx_packet) + data_size);
|
||||
packet->hops = 0;
|
||||
packet->type = type;
|
||||
|
||||
addr32_out(packet->dest_net, dest_net);
|
||||
addr48_out(packet->dest_node, dest_node);
|
||||
packet->dest_socket = dest_socket;
|
||||
|
||||
addr32_out(packet->src_net, src_net);
|
||||
addr48_out(packet->src_node, src_node);
|
||||
packet->src_socket = src_socket;
|
||||
|
||||
memcpy(packet->data, data, data_size);
|
||||
|
||||
DWORD error = ERROR_SUCCESS;
|
||||
|
||||
if(r_send(private_socket, (const void*)(packet), packet_size, 0) < 0)
|
||||
{
|
||||
error = WSAGetLastError();
|
||||
log_printf(LOG_ERROR, "Error sending DOSBox IPX packet: %s", w32_error(error));
|
||||
}
|
||||
|
||||
free(packet);
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
else{
|
||||
int packet_size = sizeof(ipx_packet) - 1 + data_size;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user