diff --git a/Makefile b/Makefile
index f447733..964185c 100644
--- a/Makefile
+++ b/Makefile
@@ -18,14 +18,14 @@ CFLAGS := -Wall -I./include/
 CXXFLAGS := -Wall -I./include/
 
 IPXWRAPPER_DEPS := src/ipxwrapper.o src/winsock.o src/ipxwrapper_stubs.o src/log.o src/common.o \
-	src/interface.o src/ipxwrapper.def
+	src/interface.o src/router.o src/ipxwrapper.def
 
 BIN_FILES := changes.txt license.txt readme.txt ipxwrapper.dll mswsock.dll wsock32.dll ipxconfig.exe
 SRC_FILES := changes.txt license.txt Makefile mkstubs.pl readme.txt src/config.h src/ipxconfig.cpp \
 	src/ipxwrapper.c src/ipxwrapper.def src/ipxwrapper.h src/ipxwrapper_stubs.txt src/log.c \
 	src/mswsock.def src/mswsock_stubs.txt src/stubdll.c src/winsock.c src/winstuff.h src/wsock32.def \
 	src/wsock32_stubs.txt src/directplay.c src/dpwsockx.def src/dpwsockx_stubs.txt src/common.c \
-	src/common.h include/dplay.h include/dplaysp.h include/dplobby.h
+	src/common.h src/router.c src/router.h include/dplay.h include/dplaysp.h include/dplobby.h
 
 all: ipxwrapper.dll wsock32.dll mswsock.dll ipxconfig.exe dpwsockx.dll
 
diff --git a/src/ipxwrapper.c b/src/ipxwrapper.c
index 2d36132..db7e9c8 100644
--- a/src/ipxwrapper.c
+++ b/src/ipxwrapper.c
@@ -29,6 +29,7 @@
 #include "ipxwrapper.h"
 #include "common.h"
 #include "interface.h"
+#include "router.h"
 
 #define DLL_UNLOAD(dll) \
 	if(dll) {\
@@ -41,7 +42,6 @@ struct ipx_interface *nics = NULL;
 ipx_host *hosts = NULL;
 SOCKET net_fd = -1;
 struct reg_global global_conf;
-static void *router_buf = NULL;
 
 HMODULE winsock2_dll = NULL;
 HMODULE mswsock_dll = NULL;
@@ -49,10 +49,9 @@ HMODULE wsock32_dll = NULL;
 
 static HANDLE mutex = NULL;
 static HANDLE router_thread = NULL;
-static DWORD router_tid = 0;
+struct router_vars *router = NULL;
 
-static int init_router(void);
-static DWORD WINAPI router_main(LPVOID argp);
+static BOOL start_router(void);
 
 BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) {
 	if(why == DLL_PROCESS_ATTACH) {
@@ -90,21 +89,23 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) {
 			return FALSE;
 		}
 		
-		if(!init_router()) {
+		if(!start_router()) {
 			return FALSE;
 		}
 	}else if(why == DLL_PROCESS_DETACH) {
-		if(router_thread && GetCurrentThreadId() != router_tid) {
-			TerminateThread(router_thread, 0);
+		if(router_thread) {
+			EnterCriticalSection(&(router->crit_sec));
+			
+			router->running = FALSE;
+			SetEvent(router->wsa_event);
+			
+			LeaveCriticalSection(&(router->crit_sec));
+			
+			WaitForSingleObject(router_thread, INFINITE);
 			router_thread = NULL;
-		}
-		
-		free(router_buf);
-		router_buf = NULL;
-		
-		if(net_fd >= 0) {
-			closesocket(net_fd);
-			net_fd = -1;
+			
+			router_destroy(router);
+			router = NULL;
 		}
 		
 		if(mutex) {
@@ -182,143 +183,24 @@ void unlock_mutex(void) {
 }
 
 /* Initialize and start the router thread */
-static int init_router(void) {
-	net_fd = r_socket(AF_INET, SOCK_DGRAM, 0);
-	if(net_fd == -1) {
-		log_printf("Failed to create network socket: %s", w32_error(WSAGetLastError()));
-		return 0;
+static BOOL start_router(void) {
+	if(!(router = router_init(FALSE))) {
+		return FALSE;
 	}
 	
-	struct sockaddr_in bind_addr;
-	bind_addr.sin_family = AF_INET;
-	bind_addr.sin_addr.s_addr = INADDR_ANY;
-	bind_addr.sin_port = htons(global_conf.udp_port);
-	
-	if(r_bind(net_fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1) {
-		log_printf("Failed to bind network socket: %s", w32_error(WSAGetLastError()));
-		return 0;
-	}
-	
-	BOOL broadcast = TRUE;
-	int bufsize = 524288;	/* 512KiB */
-	
-	r_setsockopt(net_fd, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof(BOOL));
-	r_setsockopt(net_fd, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, sizeof(int));
-	r_setsockopt(net_fd, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(int));
-	
-	router_buf = malloc(PACKET_BUF_SIZE);
-	if(!router_buf) {
-		log_printf("Not enough memory for router buffer (64KiB)");
-		return 0;
-	}
-	
-	router_thread = CreateThread(NULL, 0, &router_main, NULL, 0, &router_tid);
+	router_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&router_main, router, 0, NULL);
 	if(!router_thread) {
-		log_printf("Failed to create router thread");
-		return 0;
+		log_printf("Failed to create router thread: %s", w32_error(GetLastError()));
+		
+		router_destroy(router);
+		router = NULL;
+		
+		return FALSE;
 	}
 	
-	return 1;
-}
-
-/* Router thread main function
- *
- * The router thread recieves packets from the listening port and forwards them
- * to the UDP sockets which emulate IPX.
-*/
-static DWORD WINAPI router_main(LPVOID notused) {
-	ipx_packet *packet = router_buf;
-	int addrlen, rval, sval;
-	unsigned char f6[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
-	struct sockaddr_in addr;
-	ipx_socket *sockptr;
+	net_fd = router->udp_sock;
 	
-	while(1) {
-		addrlen = sizeof(addr);
-		rval = r_recvfrom(net_fd, (char*)packet, PACKET_BUF_SIZE, 0, (struct sockaddr*)&addr, &addrlen);
-		if(rval <= 0) {
-			log_printf("Error recieving packet: %s", w32_error(WSAGetLastError()));
-			continue;
-		}
-		
-		if(global_conf.filter) {
-			struct ipx_interface *nic = nics;
-			
-			while(nic) {
-				if((nic->ipaddr & nic->netmask) == (addr.sin_addr.s_addr & nic->netmask)) {
-					break;
-				}
-				
-				nic = nic->next;
-			}
-			
-			if(!nic) {
-				/* Packet not recieved from subnet of an enabled interface */
-				continue;
-			}
-		}
-		
-		packet->size = ntohs(packet->size);
-		
-		if(packet->size > MAX_PACKET_SIZE || packet->size+sizeof(ipx_packet)-1 != rval) {
-			log_printf("Recieved packet with incorrect size field, discarding");
-			continue;
-		}
-		
-		lock_mutex();
-		
-		add_host(packet->src_net, packet->src_node, addr.sin_addr.s_addr);
-		
-		for(sockptr = sockets; sockptr; sockptr = sockptr->next) {
-			if(
-				sockptr->flags & IPX_RECV &&
-				(
-					!(sockptr->flags & IPX_FILTER) ||
-					packet->ptype == sockptr->f_ptype
-				) && ((
-					sockptr->flags & IPX_BOUND &&
-					packet->dest_socket == sockptr->socket &&
-					(
-						memcmp(packet->dest_net, sockptr->nic->ipx_net, 4) == 0 ||
-						(
-							memcmp(packet->dest_net, f6, 4) == 0 &&
-							(!global_conf.w95_bug || sockptr->flags & IPX_BROADCAST)
-						)
-					) && (
-						memcmp(packet->dest_node, sockptr->nic->ipx_node, 6) == 0 ||
-						(
-							memcmp(packet->dest_node, f6, 6) == 0 &&
-							(!global_conf.w95_bug || sockptr->flags & IPX_BROADCAST)
-						)
-					)
-				) || (
-					sockptr->flags & IPX_EX_BOUND &&
-					packet->dest_socket == sockptr->ex_socket &&
-					(
-						memcmp(packet->dest_net, sockptr->ex_nic->ipx_net, 4) == 0 ||
-						memcmp(packet->dest_net, f6, 4) == 0
-					) && (
-						memcmp(packet->dest_node, sockptr->ex_nic->ipx_node, 6) == 0 ||
-						memcmp(packet->dest_node, f6, 6) == 0
-					)
-				))
-			) {
-				addrlen = sizeof(addr);
-				if(r_getsockname(sockptr->fd, (struct sockaddr*)&addr, &addrlen) == -1) {
-					continue;
-				}
-				
-				sval = r_sendto(sockptr->fd, (char*)packet, rval, 0, (struct sockaddr*)&addr, addrlen);
-				if(sval == -1) {
-					log_printf("Error relaying packet: %s", w32_error(WSAGetLastError()));
-				}
-			}
-		}
-		
-		unlock_mutex();
-	}
-	
-	return 0;
+	return TRUE;
 }
 
 /* Add a host to the hosts list or update an existing one */
diff --git a/src/ipxwrapper.h b/src/ipxwrapper.h
index 9abb471..ecb675d 100644
--- a/src/ipxwrapper.h
+++ b/src/ipxwrapper.h
@@ -25,6 +25,7 @@
 #include <stdio.h>
 
 #include "config.h"
+#include "router.h"
 
 /* Maximum UDP data size is 65467, we use a smaller value to ensure we have
  * plenty of space to play with for headers, etc
@@ -65,8 +66,8 @@ struct ipx_socket {
 	uint8_t f_ptype;	/* Undefined when IPX_FILTER isn't set */
 	
 	/* The following values are undefined when IPX_BOUND is not set */
-	struct ipx_interface *nic;
-	uint16_t socket; /* Stored in NETWORK BYTE ORDER */
+	struct sockaddr_ipx addr;
+	uint32_t nic_bcast;
 	
 	/* Extra bind address, only used for receiving packets.
 	 * Only defined when IPX_EX_BOUND is set.
@@ -107,6 +108,7 @@ extern struct ipx_interface *nics;
 extern ipx_host *hosts;
 extern SOCKET net_fd;
 extern struct reg_global global_conf;
+extern struct router_vars *router;
 
 extern HMODULE winsock2_dll;
 extern HMODULE mswsock_dll;
diff --git a/src/ipxwrapper_stubs.txt b/src/ipxwrapper_stubs.txt
index cab1044..d5e2a6b 100644
--- a/src/ipxwrapper_stubs.txt
+++ b/src/ipxwrapper_stubs.txt
@@ -8,6 +8,10 @@ ntohl
 htons
 ntohs
 select
+WSACreateEvent
+WSAEventSelect
+WSACloseEvent
+WSAResetEvent
 r_EnumProtocolsA
 r_EnumProtocolsW
 r_WSARecvEx
diff --git a/src/router.c b/src/router.c
index 1b03f1d..6b2c737 100644
--- a/src/router.c
+++ b/src/router.c
@@ -72,8 +72,8 @@ struct router_vars *router_init(BOOL global) {
 	struct sockaddr_in addr;
 	
 	addr.sin_family = AF_INET;
-	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-	addr.sin_port = 9999;
+	addr.sin_addr.s_addr = INADDR_ANY;
+	addr.sin_port = htons(global_conf.udp_port);
 	
 	if(bind(router->udp_sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
 		log_printf("Error binding UDP socket: %s", w32_error(WSAGetLastError()));
@@ -143,24 +143,28 @@ void router_destroy(struct router_vars *router) {
 DWORD router_main(void *arg) {
 	struct router_vars *router = arg;
 	
+	const unsigned char f6[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
+	
 	while(1) {
 		WaitForSingleObject(router->wsa_event, INFINITE);
 		
 		EnterCriticalSection(&(router->crit_sec));
 		
+		WSAResetEvent(router->wsa_event);
+		
 		if(!router->running) {
 			LeaveCriticalSection(&(router->crit_sec));
 			return 0;
 		}
 		
+		LeaveCriticalSection(&(router->crit_sec));
+		
 		struct sockaddr_in addr;
 		int addrlen = sizeof(addr);
 		
-		int len = recvfrom(router->udp_sock, router->recvbuf, PACKET_BUF_SIZE, 0, (struct sockaddr*)&addr, &addrlen);
+		int len = r_recvfrom(router->udp_sock, router->recvbuf, PACKET_BUF_SIZE, 0, (struct sockaddr*)&addr, &addrlen);
 		if(len == -1) {
-			LeaveCriticalSection(&(router->crit_sec));
-			
-			if(WSAGetLastError() == WSAEWOULDBLOCK) {
+			if(WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAECONNRESET) {
 				continue;
 			}
 			
@@ -168,6 +172,8 @@ DWORD router_main(void *arg) {
 			return 1;
 		}
 		
+		EnterCriticalSection(&(router->crit_sec));
+		
 		ipx_packet *packet = (ipx_packet*)router->recvbuf;
 		
 		/* Check that the packet arrived from the subnet of an enabled network
@@ -186,6 +192,7 @@ DWORD router_main(void *arg) {
 			}
 			
 			if(!iface) {
+				LeaveCriticalSection(&(router->crit_sec));
 				continue;
 			}
 		}
@@ -193,7 +200,7 @@ DWORD router_main(void *arg) {
 		packet->size = ntohs(packet->size);
 		
 		if(packet->size > MAX_PACKET_SIZE || packet->size + sizeof(ipx_packet) - 1 != len) {
-			log_printf("Recieved packet with incorrect size field, discarding");
+			LeaveCriticalSection(&(router->crit_sec));
 			continue;
 		}
 		
@@ -202,8 +209,6 @@ DWORD router_main(void *arg) {
 		struct router_addr *ra = router->addrs;
 		
 		while(ra) {
-			unsigned char f6[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
-			
 			if(
 				ra->local_port &&
 				(ra->filter_ptype < 0 || ra->filter_ptype == packet->ptype) &&
@@ -214,7 +219,7 @@ DWORD router_main(void *arg) {
 				addr.sin_addr.s_addr = inet_addr("127.0.0.1");
 				addr.sin_port = ra->local_port;
 				
-				if(sendto(router->udp_sock, (char*)packet, len, 0, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+				if(r_sendto(router->udp_sock, (char*)packet, len, 0, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
 					log_printf("Error relaying packet: %s", w32_error(WSAGetLastError()));
 				}
 			}
@@ -228,7 +233,20 @@ DWORD router_main(void *arg) {
 	return 0;
 }
 
-int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr) {
+int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast) {
+	/* Network number 00:00:00:00 is specified as the "current" network, this code
+	 * treats it as a wildcard when used for the network OR node numbers.
+	 *
+	 * According to MSDN 6, IPX socket numbers are unique to systems rather than
+	 * interfaces and as such, the same socket number cannot be bound to more than
+	 * one interface, my code lacks any "catch all" address like INADDR_ANY as I have
+	 * not found any mentions of an equivalent address for IPX. This means that a
+	 * given socket number may only be used on one interface.
+	 *
+	 * If you know the above information about IPX socket numbers to be incorrect,
+	 * PLEASE email me with corrections!
+	*/
+	
 	struct ipx_interface *ifaces = get_interfaces(-1), *iface;
 	unsigned char z6[] = {0,0,0,0,0,0};
 	
@@ -253,6 +271,8 @@ int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct
 	memcpy(addr->sa_netnum, iface->ipx_net, 4);
 	memcpy(addr->sa_nodenum, iface->ipx_node, 6);
 	
+	*nic_bcast = iface->bcast;
+	
 	free_interfaces(ifaces);
 	
 	EnterCriticalSection(&(router->crit_sec));
@@ -352,7 +372,7 @@ void router_set_port(struct router_vars *router, SOCKET control, SOCKET sock, ui
 	LeaveCriticalSection(&(router->crit_sec));
 }
 
-void router_close(struct router_vars *router, SOCKET control, SOCKET sock) {
+void router_unbind(struct router_vars *router, SOCKET control, SOCKET sock) {
 	EnterCriticalSection(&(router->crit_sec));
 	
 	struct router_addr *addr = router->addrs, *prev = NULL;
diff --git a/src/router.h b/src/router.h
index b1f1f53..3d8c939 100644
--- a/src/router.h
+++ b/src/router.h
@@ -61,9 +61,11 @@ struct router_vars {
 struct router_vars *router_init(BOOL global);
 void router_destroy(struct router_vars *router);
 
-int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr);
+DWORD router_main(void *arg);
+
+int router_bind(struct router_vars *router, SOCKET control, SOCKET sock, struct sockaddr_ipx *addr, uint32_t *nic_bcast);
 void router_set_port(struct router_vars *router, SOCKET control, SOCKET sock, uint16_t port);
-void router_close(struct router_vars *router, SOCKET control, SOCKET sock);
+void router_unbind(struct router_vars *router, SOCKET control, SOCKET sock);
 void router_set_filter(struct router_vars *router, SOCKET control, SOCKET sock, int ptype);
 
 #endif /* !IPXWRAPPER_ROUTER_H */
diff --git a/src/winsock.c b/src/winsock.c
index e51d6c4..5d7bd50 100644
--- a/src/winsock.c
+++ b/src/winsock.c
@@ -26,6 +26,7 @@
 #include "ipxwrapper.h"
 #include "common.h"
 #include "interface.h"
+#include "router.h"
 
 INT APIENTRY EnumProtocolsA(LPINT protocols, LPVOID buf, LPDWORD bsptr) {
 	int bufsize = *bsptr, rval, i, want_ipx = 0;
@@ -180,6 +181,8 @@ int WSAAPI closesocket(SOCKET fd) {
 	
 	log_printf("IPX socket closed (fd = %d)", fd);
 	
+	router_unbind(router, 0, fd);
+	
 	if(ptr == sockets) {
 		sockets = ptr->next;
 		free(ptr);
@@ -201,122 +204,61 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) {
 	ipx_socket *ptr = get_socket(fd);
 	
 	if(ptr) {
-		struct sockaddr_ipx *ipxaddr = (struct sockaddr_ipx*)addr;
+		struct sockaddr_ipx ipxaddr;
 		char net_s[12], node_s[18];
 		
-		NET_TO_STRING(net_s, ipxaddr->sa_netnum);
-		NODE_TO_STRING(node_s, ipxaddr->sa_nodenum);
+		if(addrlen < sizeof(ipxaddr)) {
+			RETURN_WSA(WSAEFAULT, -1);
+		}
 		
-		log_printf("bind(%d, net=%s node=%s socket=%hu)", fd, net_s, node_s, ntohs(ipxaddr->sa_socket));
+		memcpy(&ipxaddr, addr, sizeof(ipxaddr));
+		
+		NET_TO_STRING(net_s, ipxaddr.sa_netnum);
+		NODE_TO_STRING(node_s, ipxaddr.sa_nodenum);
+		
+		log_printf("bind(%d, net=%s node=%s socket=%hu)", fd, net_s, node_s, ntohs(ipxaddr.sa_socket));
 		
 		if(ptr->flags & IPX_BOUND) {
 			log_printf("bind failed: socket already bound");
 			RETURN_WSA(WSAEINVAL, -1);
 		}
 		
-		/* Network number 00:00:00:00 is specified as the "current" network, this code
-		 * treats it as a wildcard when used for the network OR node numbers.
-		 *
-		 * According to MSDN 6, IPX socket numbers are unique to systems rather than
-		 * interfaces and as such, the same socket number cannot be bound to more than
-		 * one interface, my code lacks any "catch all" address like INADDR_ANY as I have
-		 * not found any mentions of an equivalent address for IPX. This means that a
-		 * given socket number may only be used on one interface.
-		 *
-		 * If you know the above information about IPX socket numbers to be incorrect,
-		 * PLEASE email me with corrections!
-		*/
-		
-		unsigned char z6[] = {0,0,0,0,0,0};
-		struct ipx_interface *nic = nics;
-		
-		while(nic) {
-			if(
-				(memcmp(ipxaddr->sa_netnum, nic->ipx_net, 4) == 0 || memcmp(ipxaddr->sa_netnum, z6, 4) == 0) &&
-				(memcmp(ipxaddr->sa_nodenum, nic->ipx_node, 6) == 0 || memcmp(ipxaddr->sa_nodenum, z6, 6) == 0)
-			) {
-				break;
-			}
-			
-			nic = nic->next;
+		if(router_bind(router, 0, fd, &ipxaddr, &(ptr->nic_bcast)) == -1) {
+			RETURN(-1);
 		}
 		
-		if(!nic) {
-			log_printf("bind failed: no such address");
-			RETURN_WSA(WSAEADDRNOTAVAIL, -1);
-		}
+		NET_TO_STRING(net_s, ipxaddr.sa_netnum);
+		NODE_TO_STRING(node_s, ipxaddr.sa_nodenum);
 		
-		ptr->nic = nic;
-		
-		if(ipxaddr->sa_socket == 0) {
-			/* Automatic socket allocations start at 1024, I have no idea if
-			 * this is normal IPX behaviour, but IP does it and it doesn't seem
-			 * to interfere with any IPX software I've tested.
-			*/
-			
-			uint16_t s = 1024;
-			ipx_socket *socket = sockets;
-			
-			while(socket) {
-				if(ntohs(socket->socket) == s && socket->flags & IPX_BOUND) {
-					if(s == 65535) {
-						log_printf("bind failed: out of sockets?!");
-						RETURN_WSA(WSAEADDRNOTAVAIL, -1);
-					}
-					
-					s++;
-					socket = sockets;
-					
-					continue;
-				}
-				
-				socket = socket->next;
-			}
-			
-			ptr->socket = htons(s);
-		}else{
-			/* Test if any bound socket is using the requested socket number. */
-			
-			ipx_socket *socket = sockets;
-			
-			while(socket) {
-				if(socket->socket == ipxaddr->sa_socket && socket->flags & IPX_BOUND) {
-					log_printf("bind failed: requested socket in use");
-					RETURN_WSA(WSAEADDRINUSE, -1);
-				}
-				
-				socket = socket->next;
-			}
-			
-			ptr->socket = ipxaddr->sa_socket;
-		}
-		
-		NET_TO_STRING(net_s, nic->ipx_net);
-		NODE_TO_STRING(node_s, nic->ipx_node);
-		
-		log_printf("bind address: net=%s node=%s socket=%hu", net_s, node_s, ntohs(ptr->socket));
-		
-		/* TODO: Bind fake socket in socket() call rather than here?
-		 *
-		 * I think I put the bind() call for it here so that the fd given to the
-		 * program would be in the expected un-bound state, although I'm not sure
-		 * if there are any winsock calls it could ONLY make on such a socket.
-		*/
+		log_printf("bind address: net=%s node=%s socket=%hu", net_s, node_s, ntohs(ipxaddr.sa_socket));
 		
 		struct sockaddr_in bind_addr;
 		bind_addr.sin_family = AF_INET;
-		bind_addr.sin_port = 0;
 		bind_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+		bind_addr.sin_port = 0;
 		
-		int rval = r_bind(fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr));
-		
-		if(rval == 0) {
-			ptr->flags |= IPX_BOUND;
-		}else{
-			log_printf("Binding fake socket failed: %s", w32_error(WSAGetLastError()));
+		if(r_bind(fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1) {
+			log_printf("Binding local UDP socket failed: %s", w32_error(WSAGetLastError()));
+			
+			router_unbind(router, 0, fd);
+			RETURN(-1);
 		}
 		
-		RETURN(rval);
+		int al = sizeof(bind_addr);
+		
+		if(r_getsockname(fd, (struct sockaddr*)&bind_addr, &al) == -1) {
+			log_printf("getsockname failed: %s", w32_error(WSAGetLastError()));
+			
+			router_unbind(router, 0, fd);
+			RETURN(-1);
+		}
+		
+		memcpy(&(ptr->addr), &ipxaddr, sizeof(ipxaddr));
+		ptr->flags |= IPX_BOUND;
+		
+		router_set_port(router, 0, fd, bind_addr.sin_port);
+		
+		RETURN(0);
 	}else{
 		RETURN(r_bind(fd, addr, addrlen));
 	}
@@ -326,61 +268,10 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) {
  * Attempts to bind socket 0 will really bind socket 0
 */
 int ipx_ex_bind(SOCKET fd, const struct sockaddr_ipx *ipxaddr) {
-	ipx_socket *ptr = get_socket(fd);
-	
-	if(!ipxaddr) {
-		/* Call with NULL address to remove extra bind */
-		log_printf("ipx_ex_bind(%d, NULL)", fd);
-		
-		ptr->flags &= ~IPX_EX_BOUND;
-		RETURN(0);
-	}
-	
-	char net_s[12], node_s[18];
-	
-	NET_TO_STRING(net_s, ipxaddr->sa_netnum);
-	NODE_TO_STRING(node_s, ipxaddr->sa_nodenum);
-	
-	log_printf("ipx_ex_bind(%d, net=%s node=%s socket=%hu)", fd, net_s, node_s, ntohs(ipxaddr->sa_socket));
-	
-	if(!(ptr->flags & IPX_BOUND)) {
-		log_printf("ipx_ex_bind: Socket is not bound");
-		RETURN_WSA(WSAEINVAL, -1);
-	}
-	
-	unsigned char z6[] = {0,0,0,0,0,0};
-	struct ipx_interface *nic = nics;
-	
-	while(nic) {
-		if(
-			(memcmp(ipxaddr->sa_netnum, nic->ipx_net, 4) == 0 || memcmp(ipxaddr->sa_netnum, z6, 4) == 0) &&
-			(memcmp(ipxaddr->sa_nodenum, nic->ipx_node, 6) == 0 || memcmp(ipxaddr->sa_nodenum, z6, 6) == 0)
-		) {
-			break;
-		}
-		
-		nic = nic->next;
-	}
-	
-	if(!nic) {
-		log_printf("ipx_ex_bind: no such address");
-		RETURN_WSA(WSAEADDRNOTAVAIL, -1);
-	}
-	
-	NET_TO_STRING(net_s, nic->ipx_net);
-	NODE_TO_STRING(node_s, nic->ipx_node);
-	
-	log_printf("bind address: net=%s node=%s socket=%hu", net_s, node_s, ntohs(ipxaddr->sa_socket));
-	
-	ptr->ex_nic = nic;
-	ptr->ex_socket = ipxaddr->sa_socket;
-	ptr->flags |= IPX_EX_BOUND;
-	
-	RETURN(0);
+	return 0;
 }
 
 int WSAAPI getsockname(SOCKET fd, struct sockaddr *addr, int *addrlen) {
-	struct sockaddr_ipx *ipxaddr = (struct sockaddr_ipx*)addr;
 	ipx_socket *ptr = get_socket(fd);
 	
 	if(ptr) {
@@ -390,11 +281,7 @@ int WSAAPI getsockname(SOCKET fd, struct sockaddr *addr, int *addrlen) {
 				RETURN_WSA(WSAEFAULT, -1);
 			}
 			
-			ipxaddr->sa_family = AF_IPX;
-			memcpy(ipxaddr->sa_netnum, ptr->nic->ipx_net, 4);
-			memcpy(ipxaddr->sa_nodenum, ptr->nic->ipx_node, 6);
-			ipxaddr->sa_socket = ptr->socket;
-			
+			memcpy(addr, &(ptr->addr), sizeof(ptr->addr));
 			*addrlen = sizeof(struct sockaddr_ipx);
 			
 			RETURN(0);
@@ -629,11 +516,16 @@ int WSAAPI setsockopt(SOCKET fd, int level, int optname, const char FAR *optval,
 				sockptr->f_ptype = *intval;
 				sockptr->flags |= IPX_FILTER;
 				
+				router_set_filter(router, 0, fd, *intval);
+				
 				RETURN(0);
 			}
 			
 			if(optname == IPX_STOPFILTERPTYPE) {
 				sockptr->flags &= ~IPX_FILTER;
+				
+				router_set_filter(router, 0, fd, -1);
+				
 				RETURN(0);
 			}
 			
@@ -705,12 +597,12 @@ int WSAAPI sendto(SOCKET fd, const char *buf, int len, int flags, const struct s
 		unsigned char z6[] = {0,0,0,0,0,0};
 		
 		if(memcmp(packet->dest_net, z6, 4) == 0) {
-			memcpy(packet->dest_net, sockptr->nic->ipx_net, 4);
+			memcpy(packet->dest_net, sockptr->addr.sa_netnum, 4);
 		}
 		
-		memcpy(packet->src_net, sockptr->nic->ipx_net, 4);
-		memcpy(packet->src_node, sockptr->nic->ipx_node, 6);
-		packet->src_socket = sockptr->socket;
+		memcpy(packet->src_net, sockptr->addr.sa_netnum, 4);
+		memcpy(packet->src_node, sockptr->addr.sa_nodenum, 6);
+		packet->src_socket = sockptr->addr.sa_socket;
 		
 		packet->size = htons(len);
 		memcpy(packet->data, buf, len);
@@ -720,7 +612,7 @@ int WSAAPI sendto(SOCKET fd, const char *buf, int len, int flags, const struct s
 		struct sockaddr_in saddr;
 		saddr.sin_family = AF_INET;
 		saddr.sin_port = htons(global_conf.udp_port);
-		saddr.sin_addr.s_addr = (host ? host->ipaddr : (global_conf.bcast_all ? INADDR_BROADCAST : sockptr->nic->bcast));
+		saddr.sin_addr.s_addr = (host ? host->ipaddr : (global_conf.bcast_all ? INADDR_BROADCAST : sockptr->nic_bcast));
 		
 		int sval = r_sendto(net_fd, (char*)packet, psize, 0, (struct sockaddr*)&saddr, sizeof(saddr));
 		if(sval == -1) {
@@ -744,6 +636,7 @@ int PASCAL shutdown(SOCKET fd, int cmd) {
 		
 		if(cmd == SD_RECEIVE || cmd == SD_BOTH) {
 			sockptr->flags &= ~IPX_RECV;
+			router_set_port(router, 0, fd, 0);
 		}
 		
 		RETURN(0);