blob: 10fe2fd76333dbca4e40d98fcf0ecc363d3d2b11 [file]
/*
* router.cpp - ip router
*
* Basilisk II (C) 1997-2008 Christian Bauer
*
* Windows platform specific code copyright (C) Lauri Pesonen
*
* 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
*/
/*
* This could be implemented by writing three (9x,nt,2k)
* NDIS filter drivers. No thanks.
* But this is not easy either.
*/
#include "sysdeps.h"
#include "main.h"
#include <process.h>
#include "cpu_emulation.h"
#include "prefs.h"
#include "ether_windows.h"
#include "ether.h"
#include "router.h"
#include "router_types.h"
#include "dynsockets.h"
#include "ipsocket.h"
#include "iphelp.h"
#include "arp.h"
#include "icmp.h"
#include "udp.h"
#include "tcp.h"
#include "ftp.h"
#include "mib/interfaces.h"
#include "dump.h"
#if DEBUG
#pragma optimize("",off)
#endif
#include "debug.h"
uint16 next_ip_ident_number = 1;
uint32 macos_ip_address = 0;
const uint8 router_mac_addr[6] = { '4', '2', '6', '7', '7', '9' };
uint32 router_ip_address = 0;
bool raw_sockets_available = false;
// Protected data.
CRITICAL_SECTION router_section;
bool is_router_shutting_down = false;
static HANDLE r_handle = 0;
static unsigned int rh_tid = 0;
static void write_ip4( ip_t *ip, int len )
{
if(len < sizeof(ip_t)) {
D(bug("Too small ip packet(%d), dropped\r\n", len));
} else {
uint8 proto = ip->proto;
// This is a router, decrement the hop count
if( --ip->ttl == 0 ) {
// Most likely this is some Mac traceroute app
D(bug("ip packet ttl expired, proto=%d.\r\n", proto));
error_winsock_2_icmp( WSAETTLEXCEEDED, ip, len );
} else {
switch( proto ) {
case ip_proto_icmp:
write_icmp( (icmp_t *)ip, len );
break;
case ip_proto_tcp:
write_tcp( (tcp_t *)ip, len );
break;
case ip_proto_udp:
write_udp( (udp_t *)ip, len );
break;
default:
D(bug("write_ip4() len=%d, proto=%d\r\n", len, proto));
break;
}
}
}
}
bool router_write_packet(uint8 *packet, int len)
{
bool result = false;
if( len >= 14 ) {
switch( ntohs( ((mac_t *)packet)->type ) ) {
case mac_type_ip4:
write_ip4( (ip_t *)packet, len );
result = true;
break;
case mac_type_ip6:
D(bug("write_ip6() len=%d; unsupported.\r\n", len));
result = true;
break;
case mac_type_arp:
result = write_arp( (arp_t *)packet, len );
break;
}
}
return result;
}
bool router_read_packet(uint8 *packet, int len)
{
bool result = false;
if( len >= 14 ) {
switch( ntohs( ((mac_t *)packet)->type ) ) {
case mac_type_ip4:
case mac_type_ip6:
case mac_type_arp:
result = true;
break;
}
}
return result;
}
/*
This has nothing to do with TCP TIME_WAITs or CLOSE_WAITs,
the thread is needed to close down expired udp sockets.
Arguably an ugly hack, but needed since there is no way to
listen to all ports w/o writing another ndis filter driver
*/
static unsigned int WINAPI router_expire_thread(void *arg)
{
while(!is_router_shutting_down) {
close_old_sockets();
Sleep(1000);
}
return 0;
}
bool router_init(void)
{
InitializeCriticalSection( &router_section );
if(dynsockets_init()) {
char me[128];
if( _gethostname(me, sizeof(me)) == SOCKET_ERROR ) {
D(bug("gethostname() failed, error = %d\r\n", _WSAGetLastError()));
} else {
struct hostent *hent = _gethostbyname(me);
if( hent == NULL ) {
D(bug("gethostbyname() failed, error = %d\r\n", _WSAGetLastError()));
} else {
struct in_addr *ina = (struct in_addr *) *hent->h_addr_list;
router_ip_address = ntohl(ina->s_addr);
D(bug("router protocol address seems to be %s (used only in icmp error messages)\r\n", _inet_ntoa(*ina)));
}
}
is_router_shutting_down = false;
r_handle = (HANDLE)_beginthreadex( 0, 0, router_expire_thread, 0, 0, &rh_tid );
init_interfaces();
init_tcp();
init_udp();
init_ftp();
return true;
}
return false;
}
void router_final(void)
{
final_interfaces();
stop_icmp_listen();
close_all_sockets();
if(r_handle) {
is_router_shutting_down = true;
WaitForSingleObject( r_handle, INFINITE );
final_tcp();
final_udp();
dynsockets_final();
}
DeleteCriticalSection( &router_section );
}