shithub: qk1

Download patch

ref: 37154b67a6dab963885ab645b1ecd328affd7708
parent: 60dbaf4419267422713bbaac8e58cd20efd9bbd6
author: qwx <>
date: Fri Dec 7 20:49:12 EST 2018

implement networking

use plan9 syntax for connect:
connect host
connect host!port
host can be a sysname, a domain, or an ip address

- add workaround for servers replying from multiple ports: listen for a short
  while when connecting. this means that we announce an address, and for
  multiple instances on each host, each needs to set port to a different value.
  this allows qk1 to connect to unix/windows servers (not an issue on plan 9).
- remove listener toggle: only listen when necessary
- remove idgods backdoor
- remove broadcasting code: just use connect
- fix menus

--- a/dat.h
+++ b/dat.h
@@ -13,7 +13,9 @@
 	Nsavver = 5,
 	Nparms = 16,
 
-	Te9 = 1000000000
+	Te9 = 1000000000,
+
+	Udpport = 26000,
 };
 
 extern char fsdir[];
@@ -22,7 +24,7 @@
 extern char savs[][Nsavcm];
 extern int savcanld[];
 
-extern int dedicated, listener;
+extern int dedicated;
 
 enum{
 	Fpsmin = 10,
--- a/host.c
+++ b/host.c
@@ -128,9 +128,8 @@
 {
 	svs.maxclients = 1;
 	cls.state = ca_disconnected;
-	if(listener){
-		if(dedicated)
-			cls.state = ca_dedicated;
+	if(dedicated){
+		cls.state = ca_dedicated;
 		svs.maxclients = MAX_SCOREBOARD;
 	}
 	if (svs.maxclients < 1)
@@ -328,7 +327,7 @@
 
 	if (!sv.active)
 		return;
-
+	UDP_Listen(0);
 	sv.active = false;
 
 // stop all client sounds immediately
@@ -471,8 +470,6 @@
 
 // process console commands
 	Cbuf_Execute ();
-
-	NET_Poll();
 
 // if running the server locally, make intentions now
 	if (sv.active)
--- a/host_cmd.c
+++ b/host_cmd.c
@@ -56,10 +56,6 @@
 
 	print ("host:    %s\n", Cvar_VariableString ("hostname"));
 	print ("version: %4.2f\n", VERSION);
-	if (tcpipAvailable)
-		print ("tcp/ip:  %s\n", my_tcpip_address);
-	if (ipxAvailable)
-		print ("ipx:     %s\n", my_ipx_address);
 	print ("map:     %s\n", sv.name);
 	print ("players: %d active (%d max)\n\n", net_activeconnections, svs.maxclients);
 	for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
@@ -98,7 +94,7 @@
 		return;
 	}
 
-	if (pr_global_struct->deathmatch && !host_client->privileged)
+	if (pr_global_struct->deathmatch)
 		return;
 
 	sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE;
@@ -116,7 +112,7 @@
 		return;
 	}
 
-	if (pr_global_struct->deathmatch && !host_client->privileged)
+	if (pr_global_struct->deathmatch)
 		return;
 
 	sv_player->v.flags = (int)sv_player->v.flags ^ FL_NOTARGET;
@@ -136,7 +132,7 @@
 		return;
 	}
 
-	if (pr_global_struct->deathmatch && !host_client->privileged)
+	if (pr_global_struct->deathmatch)
 		return;
 
 	if (sv_player->v.movetype != MOVETYPE_NOCLIP)
@@ -168,7 +164,7 @@
 		return;
 	}
 
-	if (pr_global_struct->deathmatch && !host_client->privileged)
+	if (pr_global_struct->deathmatch)
 		return;
 
 	if (sv_player->v.movetype != MOVETYPE_FLY)
@@ -404,59 +400,7 @@
 	Con_Printf ("Exe: 00:00:00 Jun 22 1996\n");
 }
 
-#ifdef IDGODS
-void Host_Please_f (void)
-{
-	client_t *cl;
-	int			j;
-	
-	if (cmd_source != src_command)
-		return;
 
-	if(Cmd_Argc() == 3 && strcmp(Cmd_Argv(1), "#") == 0)
-	{
-		j = atof(Cmd_Argv(2)) - 1;
-		if (j < 0 || j >= svs.maxclients)
-			return;
-		if (!svs.clients[j].active)
-			return;
-		cl = &svs.clients[j];
-		if (cl->privileged)
-		{
-			cl->privileged = false;
-			cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET);
-			cl->edict->v.movetype = MOVETYPE_WALK;
-			noclip_anglehack = false;
-		}
-		else
-			cl->privileged = true;
-	}
-
-	if (Cmd_Argc () != 2)
-		return;
-
-	for (j=0, cl = svs.clients ; j<svs.maxclients ; j++, cl++)
-	{
-		if (!cl->active)
-			continue;
-		if(cistrcmp(cl->name, Cmd_Argv(1)) == 0)
-		{
-			if (cl->privileged)
-			{
-				cl->privileged = false;
-				cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET);
-				cl->edict->v.movetype = MOVETYPE_WALK;
-				noclip_anglehack = false;
-			}
-			else
-				cl->privileged = true;
-			break;
-		}
-	}
-}
-#endif
-
-
 void Host_Say(qboolean teamonly)
 {
 	client_t *client;
@@ -977,7 +921,7 @@
 			return;
 		}
 	}
-	else if (pr_global_struct->deathmatch && !host_client->privileged)
+	else if (pr_global_struct->deathmatch)
 		return;
 
 	save = host_client;
@@ -1065,7 +1009,7 @@
 		return;
 	}
 
-	if (pr_global_struct->deathmatch && !host_client->privileged)
+	if (pr_global_struct->deathmatch)
 		return;
 
 	t = Cmd_Argv(1);
@@ -1431,9 +1375,6 @@
 	Cmd_AddCommand ("name", Host_Name_f);
 	Cmd_AddCommand ("noclip", Host_Noclip_f);
 	Cmd_AddCommand ("version", Host_Version_f);
-#ifdef IDGODS
-	Cmd_AddCommand ("please", Host_Please_f);
-#endif
 	Cmd_AddCommand ("say", Host_Say_f);
 	Cmd_AddCommand ("say_team", Host_Say_Team_f);
 	Cmd_AddCommand ("tell", Host_Tell_f);
--- a/menu.c
+++ b/menu.c
@@ -7,7 +7,7 @@
 char savs[Nsav][Nsavcm];
 int savcanld[Nsav];
 
-enum {m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_net, m_options, m_keys, m_help, m_quit, m_serialconfig, m_modemconfig, m_lanconfig, m_gameoptions, m_search, m_slist} m_state;
+enum {m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_net, m_options, m_keys, m_help, m_quit, m_lanconfig, m_gameoptions} m_state;
 
 void M_Menu_Main_f (void);
 	void M_Menu_SinglePlayer_f (void);
@@ -20,12 +20,8 @@
 		void M_Menu_Keys_f (void);
 	void M_Menu_Help_f (void);
 	void M_Menu_Quit_f (void);
-void M_Menu_SerialConfig_f (void);
-	void M_Menu_ModemConfig_f (void);
 void M_Menu_LanConfig_f (void);
 void M_Menu_GameOptions_f (void);
-void M_Menu_Search_f (void);
-void M_Menu_ServerList_f (void);
 
 void M_Main_Draw (void);
 	void M_SinglePlayer_Draw (void);
@@ -38,12 +34,8 @@
 		void M_Keys_Draw (void);
 	void M_Help_Draw (void);
 	void M_Quit_Draw (void);
-void M_SerialConfig_Draw (void);
-	void M_ModemConfig_Draw (void);
 void M_LanConfig_Draw (void);
 void M_GameOptions_Draw (void);
-void M_Search_Draw (void);
-void M_ServerList_Draw (void);
 
 void M_Main_Key (int key);
 	void M_SinglePlayer_Key (int key);
@@ -56,12 +48,8 @@
 		void M_Keys_Key (int key);
 	void M_Help_Key (int key);
 	void M_Quit_Key (int key);
-void M_SerialConfig_Key (int key);
-	void M_ModemConfig_Key (int key);
 void M_LanConfig_Key (int key);
 void M_GameOptions_Key (int key);
-void M_Search_Key (int key);
-void M_ServerList_Key (int key);
 
 qboolean	m_entersound;		// play after drawing a frame, so caching
 								// won't disrupt the sound
@@ -73,13 +61,8 @@
 
 #define StartingGame	(m_multiplayer_cursor == 1)
 #define JoiningGame		(m_multiplayer_cursor == 0)
-#define SerialConfig	(m_net_cursor == 0)
-#define DirectConfig	(m_net_cursor == 1)
-#define	IPXConfig		(m_net_cursor == 2)
-#define	TCPIPConfig		(m_net_cursor == 3)
+#define	UDPIPConfig		(m_net_cursor == 2)
 
-void M_ConfigureNetSubsystem(void);
-
 /*
 ================
 M_DrawCharacter
@@ -569,10 +552,6 @@
 	f = (int)(host_time * 10)%6;
 
 	M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%d.lmp", f+1 ) ) );
-
-	if (serialAvailable || ipxAvailable || tcpipAvailable)
-		return;
-	M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available");
 }
 
 
@@ -601,13 +580,11 @@
 		switch (m_multiplayer_cursor)
 		{
 		case 0:
-			if (serialAvailable || ipxAvailable || tcpipAvailable)
-				M_Menu_Net_f ();
+			M_Menu_Net_f ();
 			break;
 
 		case 1:
-			if (serialAvailable || ipxAvailable || tcpipAvailable)
-				M_Menu_Net_f ();
+			M_Menu_Net_f ();
 			break;
 
 		case 2:
@@ -811,11 +788,6 @@
   " by a null-modem cable. ",
   "                        ",
 
-  " Novell network LANs    ",
-  " or Windows 95 DOS-box. ",
-  "                        ",
-  "(LAN=Local Area Network)",
-
   " Commonly used to play  ",
   " over the Internet, but ",
   " also used on a Local   ",
@@ -827,7 +799,7 @@
 	key_dest = key_menu;
 	m_state = m_net;
 	m_entersound = true;
-	m_net_items = 4;
+	m_net_items = 3;
 
 	if (m_net_cursor >= m_net_items)
 		m_net_cursor = 0;
@@ -847,10 +819,7 @@
 
 	f = 32;
 
-	if (serialAvailable)
-		p = Draw_CachePic ("gfx/netmen1.lmp");
-	else
-		p = Draw_CachePic ("gfx/dim_modm.lmp");
+	p = Draw_CachePic ("gfx/dim_modm.lmp");
 
 	if (p)
 		M_DrawTransPic (72, f, p);
@@ -857,35 +826,15 @@
 
 	f += 19;
 
-	if (serialAvailable)
-		p = Draw_CachePic ("gfx/netmen2.lmp");
-	else
-		p = Draw_CachePic ("gfx/dim_drct.lmp");
+	p = Draw_CachePic ("gfx/dim_drct.lmp");
 
 	if (p)
 		M_DrawTransPic (72, f, p);
 
 	f += 19;
-	if (ipxAvailable)
-		p = Draw_CachePic ("gfx/netmen3.lmp");
-	else
-		p = Draw_CachePic ("gfx/dim_ipx.lmp");
+	p = Draw_CachePic ("gfx/netmen4.lmp");
 	M_DrawTransPic (72, f, p);
 
-	f += 19;
-	if (tcpipAvailable)
-		p = Draw_CachePic ("gfx/netmen4.lmp");
-	else
-		p = Draw_CachePic ("gfx/dim_tcp.lmp");
-	M_DrawTransPic (72, f, p);
-
-	if (m_net_items == 5)	// JDC, could just be removed
-	{
-		f += 19;
-		p = Draw_CachePic ("gfx/netmen5.lmp");
-		M_DrawTransPic (72, f, p);
-	}
-
 	f = (320-26*8)/2;
 	M_DrawTextBox (f, 134, 24, 4);
 	f += 8;
@@ -892,7 +841,6 @@
 	M_Print (f, 142, net_helpMessage[m_net_cursor*4+0]);
 	M_Print (f, 150, net_helpMessage[m_net_cursor*4+1]);
 	M_Print (f, 158, net_helpMessage[m_net_cursor*4+2]);
-	M_Print (f, 166, net_helpMessage[m_net_cursor*4+3]);
 
 	f = (int)(host_time * 10)%6;
 	M_DrawTransPic (54, 32 + m_net_cursor * 20,Draw_CachePic( va("gfx/menudot%d.lmp", f+1 ) ) );
@@ -926,35 +874,18 @@
 		switch (m_net_cursor)
 		{
 		case 0:
-			M_Menu_SerialConfig_f ();
-			break;
-
 		case 1:
-			M_Menu_SerialConfig_f ();
 			break;
-
 		case 2:
 			M_Menu_LanConfig_f ();
 			break;
 
-		case 3:
-			M_Menu_LanConfig_f ();
+		default:
 			break;
-
-		case 4:
-// multiprotocol
-			break;
 		}
 	}
-
-	if (m_net_cursor == 0 && !serialAvailable)
+	if (m_net_cursor == 0 || m_net_cursor == 1)
 		goto again;
-	if (m_net_cursor == 1 && !serialAvailable)
-		goto again;
-	if (m_net_cursor == 2 && !ipxAvailable)
-		goto again;
-	if (m_net_cursor == 3 && !tcpipAvailable)
-		goto again;
 }
 
 //=============================================================================
@@ -1536,474 +1467,12 @@
 }
 
 //=============================================================================
-
-/* SERIAL CONFIG MENU */
-
-int		serialConfig_cursor;
-int		serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132};
-#define	NUM_SERIALCONFIG_CMDS	6
-
-static int ISA_uarts[]	= {0x3f8,0x2f8,0x3e8,0x2e8};
-static int ISA_IRQs[]	= {4,3,4,3};
-int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600};
-
-int		serialConfig_comport;
-int		serialConfig_irq ;
-int		serialConfig_baud;
-char	serialConfig_phone[16];
-
-void M_Menu_SerialConfig_f (void)
-{
-	int		n;
-	int		port;
-	int		baudrate;
-	qboolean	useModem;
-
-	key_dest = key_menu;
-	m_state = m_serialconfig;
-	m_entersound = true;
-	if (JoiningGame && SerialConfig)
-		serialConfig_cursor = 4;
-	else
-		serialConfig_cursor = 5;
-
-	(*GetComPortConfig) (0, &port, &serialConfig_irq, &baudrate, &useModem);
-
-	// map uart's port to COMx
-	for (n = 0; n < 4; n++)
-		if (ISA_uarts[n] == port)
-			break;
-	if (n == 4)
-	{
-		n = 0;
-		serialConfig_irq = 4;
-	}
-	serialConfig_comport = n + 1;
-
-	// map baudrate to index
-	for (n = 0; n < 6; n++)
-		if (serialConfig_baudrate[n] == baudrate)
-			break;
-	if (n == 6)
-		n = 5;
-	serialConfig_baud = n;
-
-	m_return_onerror = false;
-	m_return_reason[0] = 0;
-}
-
-
-void M_SerialConfig_Draw (void)
-{
-	qpic_t	*p;
-	int		basex;
-	char	*startJoin;
-	char	*directModem;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	basex = (320-p->width)/2;
-	M_DrawPic (basex, 4, p);
-
-	if (StartingGame)
-		startJoin = "New Game";
-	else
-		startJoin = "Join Game";
-	if (SerialConfig)
-		directModem = "Modem";
-	else
-		directModem = "Direct Connect";
-	M_Print (basex, 32, va ("%s - %s", startJoin, directModem));
-	basex += 8;
-
-	M_Print (basex, serialConfig_cursor_table[0], "Port");
-	M_DrawTextBox (160, 40, 4, 1);
-	M_Print (168, serialConfig_cursor_table[0], va("COM%ud", serialConfig_comport));
-
-	M_Print (basex, serialConfig_cursor_table[1], "IRQ");
-	M_DrawTextBox (160, serialConfig_cursor_table[1]-8, 1, 1);
-	M_Print (168, serialConfig_cursor_table[1], va("%ud", serialConfig_irq));
-
-	M_Print (basex, serialConfig_cursor_table[2], "Baud");
-	M_DrawTextBox (160, serialConfig_cursor_table[2]-8, 5, 1);
-	M_Print (168, serialConfig_cursor_table[2], va("%ud", serialConfig_baudrate[serialConfig_baud]));
-
-	if (SerialConfig)
-	{
-		M_Print (basex, serialConfig_cursor_table[3], "Modem Setup...");
-		if (JoiningGame)
-		{
-			M_Print (basex, serialConfig_cursor_table[4], "Phone number");
-			M_DrawTextBox (160, serialConfig_cursor_table[4]-8, 16, 1);
-			M_Print (168, serialConfig_cursor_table[4], serialConfig_phone);
-		}
-	}
-
-	if (JoiningGame)
-	{
-		M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 7, 1);
-		M_Print (basex+8, serialConfig_cursor_table[5], "Connect");
-	}
-	else
-	{
-		M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 2, 1);
-		M_Print (basex+8, serialConfig_cursor_table[5], "OK");
-	}
-
-	M_DrawCharacter (basex-8, serialConfig_cursor_table [serialConfig_cursor], 12+((int)(realtime*4)&1));
-
-	if (serialConfig_cursor == 4)
-		M_DrawCharacter (168 + 8*strlen(serialConfig_phone), serialConfig_cursor_table [serialConfig_cursor], 10+((int)(realtime*4)&1));
-
-	if (*m_return_reason)
-		M_PrintWhite (basex, 148, m_return_reason);
-}
-
-
-void M_SerialConfig_Key (int key)
-{
-	int		l;
-
-	switch (key)
-	{
-	case K_ESCAPE:
-		M_Menu_Net_f ();
-		break;
-
-	case K_UPARROW:
-		localsfx ("misc/menu1.wav");
-		serialConfig_cursor--;
-		if (serialConfig_cursor < 0)
-			serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1;
-		break;
-
-	case K_DOWNARROW:
-		localsfx ("misc/menu1.wav");
-		serialConfig_cursor++;
-		if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS)
-			serialConfig_cursor = 0;
-		break;
-
-	case K_LEFTARROW:
-		if (serialConfig_cursor > 2)
-			break;
-		localsfx ("misc/menu3.wav");
-
-		if (serialConfig_cursor == 0)
-		{
-			serialConfig_comport--;
-			if (serialConfig_comport == 0)
-				serialConfig_comport = 4;
-			serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
-		}
-
-		if (serialConfig_cursor == 1)
-		{
-			serialConfig_irq--;
-			if (serialConfig_irq == 6)
-				serialConfig_irq = 5;
-			if (serialConfig_irq == 1)
-				serialConfig_irq = 7;
-		}
-
-		if (serialConfig_cursor == 2)
-		{
-			serialConfig_baud--;
-			if (serialConfig_baud < 0)
-				serialConfig_baud = 5;
-		}
-
-		break;
-
-	case K_RIGHTARROW:
-		if (serialConfig_cursor > 2)
-			break;
-forward:
-		localsfx ("misc/menu3.wav");
-
-		if (serialConfig_cursor == 0)
-		{
-			serialConfig_comport++;
-			if (serialConfig_comport > 4)
-				serialConfig_comport = 1;
-			serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
-		}
-
-		if (serialConfig_cursor == 1)
-		{
-			serialConfig_irq++;
-			if (serialConfig_irq == 6)
-				serialConfig_irq = 7;
-			if (serialConfig_irq == 8)
-				serialConfig_irq = 2;
-		}
-
-		if (serialConfig_cursor == 2)
-		{
-			serialConfig_baud++;
-			if (serialConfig_baud > 5)
-				serialConfig_baud = 0;
-		}
-
-		break;
-
-	case K_ENTER:
-		if (serialConfig_cursor < 3)
-			goto forward;
-
-		m_entersound = true;
-
-		if (serialConfig_cursor == 3)
-		{
-			(*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
-
-			M_Menu_ModemConfig_f ();
-			break;
-		}
-
-		if (serialConfig_cursor == 4)
-		{
-			serialConfig_cursor = 5;
-			break;
-		}
-
-		// serialConfig_cursor == 5 (OK/CONNECT)
-		(*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
-
-		M_ConfigureNetSubsystem ();
-
-		if (StartingGame)
-		{
-			M_Menu_GameOptions_f ();
-			break;
-		}
-
-		m_return_state = m_state;
-		m_return_onerror = true;
-		key_dest = key_game;
-		m_state = m_none;
-
-		if (SerialConfig)
-			Cbuf_AddText (va ("connect \"%s\"\n", serialConfig_phone));
-		else
-			Cbuf_AddText ("connect\n");
-		break;
-
-	case K_BACKSPACE:
-		if (serialConfig_cursor == 4)
-		{
-			if (strlen(serialConfig_phone))
-				serialConfig_phone[strlen(serialConfig_phone)-1] = 0;
-		}
-		break;
-
-	default:
-		if (key < 32 || key > 127)
-			break;
-		if (serialConfig_cursor == 4)
-		{
-			l = strlen(serialConfig_phone);
-			if (l < 15)
-			{
-				serialConfig_phone[l+1] = 0;
-				serialConfig_phone[l] = key;
-			}
-		}
-	}
-
-	if (DirectConfig && (serialConfig_cursor == 3 || serialConfig_cursor == 4))
-		if (key == K_UPARROW)
-			serialConfig_cursor = 2;
-		else
-			serialConfig_cursor = 5;
-
-	if (SerialConfig && StartingGame && serialConfig_cursor == 4)
-		if (key == K_UPARROW)
-			serialConfig_cursor = 3;
-		else
-			serialConfig_cursor = 5;
-}
-
-//=============================================================================
-/* MODEM CONFIG MENU */
-
-int		modemConfig_cursor;
-int		modemConfig_cursor_table [] = {40, 56, 88, 120, 156};
-#define NUM_MODEMCONFIG_CMDS	5
-
-char	modemConfig_dialing;
-char	modemConfig_clear [16];
-char	modemConfig_init [32];
-char	modemConfig_hangup [16];
-
-void M_Menu_ModemConfig_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_modemconfig;
-	m_entersound = true;
-	(*GetModemConfig) (0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup);
-}
-
-
-void M_ModemConfig_Draw (void)
-{
-	qpic_t	*p;
-	int		basex;
-
-	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	basex = (320-p->width)/2;
-	M_DrawPic (basex, 4, p);
-	basex += 8;
-
-	if (modemConfig_dialing == 'P')
-		M_Print (basex, modemConfig_cursor_table[0], "Pulse Dialing");
-	else
-		M_Print (basex, modemConfig_cursor_table[0], "Touch Tone Dialing");
-
-	M_Print (basex, modemConfig_cursor_table[1], "Clear");
-	M_DrawTextBox (basex, modemConfig_cursor_table[1]+4, 16, 1);
-	M_Print (basex+8, modemConfig_cursor_table[1]+12, modemConfig_clear);
-	if (modemConfig_cursor == 1)
-		M_DrawCharacter (basex+8 + 8*strlen(modemConfig_clear), modemConfig_cursor_table[1]+12, 10+((int)(realtime*4)&1));
-
-	M_Print (basex, modemConfig_cursor_table[2], "Init");
-	M_DrawTextBox (basex, modemConfig_cursor_table[2]+4, 30, 1);
-	M_Print (basex+8, modemConfig_cursor_table[2]+12, modemConfig_init);
-	if (modemConfig_cursor == 2)
-		M_DrawCharacter (basex+8 + 8*strlen(modemConfig_init), modemConfig_cursor_table[2]+12, 10+((int)(realtime*4)&1));
-
-	M_Print (basex, modemConfig_cursor_table[3], "Hangup");
-	M_DrawTextBox (basex, modemConfig_cursor_table[3]+4, 16, 1);
-	M_Print (basex+8, modemConfig_cursor_table[3]+12, modemConfig_hangup);
-	if (modemConfig_cursor == 3)
-		M_DrawCharacter (basex+8 + 8*strlen(modemConfig_hangup), modemConfig_cursor_table[3]+12, 10+((int)(realtime*4)&1));
-
-	M_DrawTextBox (basex, modemConfig_cursor_table[4]-8, 2, 1);
-	M_Print (basex+8, modemConfig_cursor_table[4], "OK");
-
-	M_DrawCharacter (basex-8, modemConfig_cursor_table [modemConfig_cursor], 12+((int)(realtime*4)&1));
-}
-
-
-void M_ModemConfig_Key (int key)
-{
-	int		l;
-
-	switch (key)
-	{
-	case K_ESCAPE:
-		M_Menu_SerialConfig_f ();
-		break;
-
-	case K_UPARROW:
-		localsfx ("misc/menu1.wav");
-		modemConfig_cursor--;
-		if (modemConfig_cursor < 0)
-			modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1;
-		break;
-
-	case K_DOWNARROW:
-		localsfx ("misc/menu1.wav");
-		modemConfig_cursor++;
-		if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS)
-			modemConfig_cursor = 0;
-		break;
-
-	case K_LEFTARROW:
-	case K_RIGHTARROW:
-		if (modemConfig_cursor == 0)
-		{
-			if (modemConfig_dialing == 'P')
-				modemConfig_dialing = 'T';
-			else
-				modemConfig_dialing = 'P';
-			localsfx ("misc/menu1.wav");
-		}
-		break;
-
-	case K_ENTER:
-		if (modemConfig_cursor == 0)
-		{
-			if (modemConfig_dialing == 'P')
-				modemConfig_dialing = 'T';
-			else
-				modemConfig_dialing = 'P';
-			m_entersound = true;
-		}
-
-		if (modemConfig_cursor == 4)
-		{
-			(*SetModemConfig) (0, va ("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup);
-			m_entersound = true;
-			M_Menu_SerialConfig_f ();
-		}
-		break;
-
-	case K_BACKSPACE:
-		if (modemConfig_cursor == 1)
-		{
-			if (strlen(modemConfig_clear))
-				modemConfig_clear[strlen(modemConfig_clear)-1] = 0;
-		}
-
-		if (modemConfig_cursor == 2)
-		{
-			if (strlen(modemConfig_init))
-				modemConfig_init[strlen(modemConfig_init)-1] = 0;
-		}
-
-		if (modemConfig_cursor == 3)
-		{
-			if (strlen(modemConfig_hangup))
-				modemConfig_hangup[strlen(modemConfig_hangup)-1] = 0;
-		}
-		break;
-
-	default:
-		if (key < 32 || key > 127)
-			break;
-
-		if (modemConfig_cursor == 1)
-		{
-			l = strlen(modemConfig_clear);
-			if (l < 15)
-			{
-				modemConfig_clear[l+1] = 0;
-				modemConfig_clear[l] = key;
-			}
-		}
-
-		if (modemConfig_cursor == 2)
-		{
-			l = strlen(modemConfig_init);
-			if (l < 29)
-			{
-				modemConfig_init[l+1] = 0;
-				modemConfig_init[l] = key;
-			}
-		}
-
-		if (modemConfig_cursor == 3)
-		{
-			l = strlen(modemConfig_hangup);
-			if (l < 15)
-			{
-				modemConfig_hangup[l+1] = 0;
-				modemConfig_hangup[l] = key;
-			}
-		}
-	}
-}
-
-//=============================================================================
 /* LAN CONFIG MENU */
 
 int		lanConfig_cursor = -1;
-int		lanConfig_cursor_table [] = {72, 92, 124};
-#define NUM_LANCONFIG_CMDS	3
+int		lanConfig_cursor_table [] = {72, 92};
+#define NUM_LANCONFIG_CMDS	2
 
-int 	lanConfig_port;
 char	lanConfig_portname[6];
 char	lanConfig_joinname[22];
 
@@ -2012,18 +1481,9 @@
 	key_dest = key_menu;
 	m_state = m_lanconfig;
 	m_entersound = true;
-	if (lanConfig_cursor == -1)
-	{
-		if (JoiningGame && TCPIPConfig)
-			lanConfig_cursor = 2;
-		else
-			lanConfig_cursor = 1;
-	}
-	if (StartingGame && lanConfig_cursor == 2)
+	if(lanConfig_cursor == -1)
 		lanConfig_cursor = 1;
-	lanConfig_port = DEFAULTnet_hostport;
-	sprint(lanConfig_portname, "%ud", (uint)lanConfig_port);	/* FIXME */
-
+	strncpy(lanConfig_portname, myip.srv, sizeof(lanConfig_portname)-1);
 	m_return_onerror = false;
 	m_return_reason[0] = 0;
 }
@@ -2034,7 +1494,6 @@
 	qpic_t	*p;
 	int		basex;
 	char	*startJoin;
-	char	*protocol;
 
 	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
 	p = Draw_CachePic ("gfx/p_multi.lmp");
@@ -2045,18 +1504,11 @@
 		startJoin = "New Game";
 	else
 		startJoin = "Join Game";
-	if (IPXConfig)
-		protocol = "IPX";
-	else
-		protocol = "TCP/IP";
-	M_Print (basex, 32, va ("%s - %s", startJoin, protocol));
+	M_Print (basex, 32, va ("%s - %s", startJoin, "UDP/IP"));
 	basex += 8;
 
 	M_Print (basex, 52, "Address:");
-	if (IPXConfig)
-		M_Print (basex+9*8, 52, my_ipx_address);
-	else
-		M_Print (basex+9*8, 52, my_tcpip_address);
+	M_Print (basex+9*8, 52, myip.ip);
 
 	M_Print (basex, lanConfig_cursor_table[0], "Port");
 	M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
@@ -2064,10 +1516,9 @@
 
 	if (JoiningGame)
 	{
-		M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
-		M_Print (basex, 108, "Join game at:");
-		M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
-		M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
+		M_Print (basex, lanConfig_cursor_table[1], "Join game at:");
+		M_DrawTextBox (basex+8, lanConfig_cursor_table[1]+16-8, 22, 1);
+		M_Print (basex+16, lanConfig_cursor_table[1]+16, lanConfig_joinname);
 	}
 	else
 	{
@@ -2080,8 +1531,8 @@
 	if (lanConfig_cursor == 0)
 		M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
 
-	if (lanConfig_cursor == 2)
-		M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
+	if (JoiningGame && lanConfig_cursor == 1)
+		M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [1]+16, 10+((int)(realtime*4)&1));
 
 	if (*m_return_reason)
 		M_PrintWhite (basex, 148, m_return_reason);
@@ -2118,29 +1569,25 @@
 
 		m_entersound = true;
 
-		M_ConfigureNetSubsystem ();
+		Cbuf_AddText ("stopdemo\n");
+		if (UDPIPConfig)
+			Cbuf_AddText(va("port %s\n", lanConfig_portname));
 
 		if (lanConfig_cursor == 1)
 		{
-			if (StartingGame)
-			{
+			if(StartingGame){
 				M_Menu_GameOptions_f ();
 				break;
+			}else{
+				m_return_state = m_state;
+				m_return_onerror = true;
+				key_dest = key_game;
+				m_state = m_none;
+				Cbuf_AddText(va("connect \"%s\"\n", lanConfig_joinname));
 			}
-			M_Menu_Search_f();
 			break;
 		}
 
-		if (lanConfig_cursor == 2)
-		{
-			m_return_state = m_state;
-			m_return_onerror = true;
-			key_dest = key_game;
-			m_state = m_none;
-			Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
-			break;
-		}
-
 		break;
 
 	case K_BACKSPACE:
@@ -2150,7 +1597,7 @@
 				lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
 		}
 
-		if (lanConfig_cursor == 2)
+		if (JoiningGame && lanConfig_cursor == 1)
 		{
 			if (strlen(lanConfig_joinname))
 				lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
@@ -2161,7 +1608,7 @@
 		if (key < 32 || key > 127)
 			break;
 
-		if (lanConfig_cursor == 2)
+		if (JoiningGame && lanConfig_cursor == 1)
 		{
 			l = strlen(lanConfig_joinname);
 			if (l < 21)
@@ -2183,17 +1630,9 @@
 			}
 		}
 	}
-
-	if (StartingGame && lanConfig_cursor == 2)
-		if (key == K_UPARROW)
-			lanConfig_cursor = 1;
-		else
-			lanConfig_cursor = 0;
-
 	l = atoi(lanConfig_portname);
-	if (l < 65535)
-		lanConfig_port = l;
-	sprint(lanConfig_portname, "%ud", (uint)lanConfig_port);	/* FIXME */
+	if(l > 0 && l < 65535)
+		sprint(lanConfig_portname, "%d", l);
 }
 
 //=============================================================================
@@ -2634,7 +2073,6 @@
 		{
 			if (sv.active)
 				Cbuf_AddText ("disconnect\n");
-			Cbuf_AddText ("listen 0\n");	// so host_netport will be re-examined
 			Cbuf_AddText ( va ("maxplayers %ud\n", maxplayers) );
 			SCR_BeginLoadingPlaque ();
 
@@ -2654,168 +2092,6 @@
 }
 
 //=============================================================================
-/* SEARCH MENU */
-
-qboolean	searchComplete = false;
-double		searchCompleteTime;
-
-void M_Menu_Search_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_search;
-	m_entersound = false;
-	slistSilent = true;
-	slistLocal = false;
-	searchComplete = false;
-	NET_Slist_f();
-
-}
-
-
-void M_Search_Draw (void)
-{
-	qpic_t	*p;
-	int x;
-
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-	x = (320/2) - ((12*8)/2) + 4;
-	M_DrawTextBox (x-8, 32, 12, 1);
-	M_Print (x, 40, "Searching...");
-
-	if(slistInProgress)
-	{
-		NET_Poll();
-		return;
-	}
-
-	if (! searchComplete)
-	{
-		searchComplete = true;
-		searchCompleteTime = realtime;
-	}
-
-	if (hostCacheCount)
-	{
-		M_Menu_ServerList_f ();
-		return;
-	}
-
-	M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found");
-	if ((realtime - searchCompleteTime) < 3.0)
-		return;
-
-	M_Menu_LanConfig_f ();
-}
-
-
-void M_Search_Key (int) /*key*/
-{
-}
-
-//=============================================================================
-/* SLIST MENU */
-
-int		slist_cursor;
-qboolean slist_sorted;
-
-void M_Menu_ServerList_f (void)
-{
-	key_dest = key_menu;
-	m_state = m_slist;
-	m_entersound = true;
-	slist_cursor = 0;
-	m_return_onerror = false;
-	m_return_reason[0] = 0;
-	slist_sorted = false;
-}
-
-
-void M_ServerList_Draw (void)
-{
-	int n, i, j;
-	char	string [64];
-	qpic_t	*p;
-	hostcache_t temp;
-
-	if (!slist_sorted)
-	{
-		if (hostCacheCount > 1)
-		{
-			for (i = 0; i < hostCacheCount; i++)
-				for (j = i+1; j < hostCacheCount; j++)
-					if(strcmp(hostcache[j].name, hostcache[i].name) < 0)
-					{
-						memcpy(&temp, &hostcache[j], sizeof temp);
-						memcpy(&hostcache[j], &hostcache[i], sizeof temp);
-						memcpy(&hostcache[i], &temp, sizeof temp);
-					}
-		}
-		slist_sorted = true;
-	}
-
-	p = Draw_CachePic ("gfx/p_multi.lmp");
-	M_DrawPic ( (320-p->width)/2, 4, p);
-	for (n = 0; n < hostCacheCount; n++)
-	{
-		if (hostcache[n].maxusers)
-			sprint(string, "%-15.15s %-15.15s %2ud/%2ud\n", hostcache[n].name, hostcache[n].map, (uint)hostcache[n].users, (uint)hostcache[n].maxusers);	/* FIXME */
-		else
-			sprint(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
-		M_Print (16, 32 + 8*n, string);
-	}
-	M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
-
-	if (*m_return_reason)
-		M_PrintWhite (16, 148, m_return_reason);
-}
-
-
-void M_ServerList_Key (int k)
-{
-	switch (k)
-	{
-	case K_ESCAPE:
-		M_Menu_LanConfig_f ();
-		break;
-
-	case K_SPACE:
-		M_Menu_Search_f ();
-		break;
-
-	case K_UPARROW:
-	case K_LEFTARROW:
-		localsfx ("misc/menu1.wav");
-		slist_cursor--;
-		if (slist_cursor < 0)
-			slist_cursor = hostCacheCount - 1;
-		break;
-
-	case K_DOWNARROW:
-	case K_RIGHTARROW:
-		localsfx ("misc/menu1.wav");
-		slist_cursor++;
-		if (slist_cursor >= hostCacheCount)
-			slist_cursor = 0;
-		break;
-
-	case K_ENTER:
-		localsfx ("misc/menu2.wav");
-		m_return_state = m_state;
-		m_return_onerror = true;
-		slist_sorted = false;
-		key_dest = key_game;
-		m_state = m_none;
-		Cbuf_AddText ( va ("connect \"%s\"\n", hostcache[slist_cursor].cname) );
-		break;
-
-	default:
-		break;
-	}
-
-}
-
-//=============================================================================
 /* Menu Subsystem */
 
 
@@ -2906,14 +2182,6 @@
 		M_Quit_Draw ();
 		break;
 
-	case m_serialconfig:
-		M_SerialConfig_Draw ();
-		break;
-
-	case m_modemconfig:
-		M_ModemConfig_Draw ();
-		break;
-
 	case m_lanconfig:
 		M_LanConfig_Draw ();
 		break;
@@ -2921,14 +2189,6 @@
 	case m_gameoptions:
 		M_GameOptions_Draw ();
 		break;
-
-	case m_search:
-		M_Search_Draw ();
-		break;
-
-	case m_slist:
-		M_ServerList_Draw ();
-		break;
 	}
 
 	if (m_entersound)
@@ -2977,12 +2237,6 @@
 	case m_quit:
 		M_Quit_Key(key);
 		break;
-	case m_serialconfig:
-		M_SerialConfig_Key(key);
-		break;
-	case m_modemconfig:
-		M_ModemConfig_Key(key);
-		break;
 	case m_lanconfig:
 		M_LanConfig_Key(key);
 		break;
@@ -2989,26 +2243,5 @@
 	case m_gameoptions:
 		M_GameOptions_Key(key);
 		break;
-	case m_search:
-		M_Search_Key(key);
-		break;
-	case m_slist:
-		M_ServerList_Key(key);
-		break;
 	}
-}
-
-
-void M_ConfigureNetSubsystem(void)
-{
-// enable/disable net systems to match desired config
-
-	Cbuf_AddText ("stopdemo\n");
-	if (SerialConfig || DirectConfig)
-	{
-		Cbuf_AddText ("com1 enable\n");
-	}
-
-	if (IPXConfig || TCPIPConfig)
-		net_hostport = lanConfig_port;
 }
--- a/menu.h
+++ b/menu.h
@@ -1,13 +1,4 @@
 //
-// the net drivers should just set the apropriate bits in m_activenet,
-// instead of having the menu code look through their internal tables
-//
-#define	MNET_IPX		1
-#define	MNET_TCP		2
-
-extern	int	m_activenet;
-
-//
 // menus
 //
 void M_Init (void);
--- a/mkfile
+++ b/mkfile
@@ -35,7 +35,6 @@
 	mathlib.$O\
 	menu.$O\
 	model.$O\
-	net_bsd.$O\
 	net_dgrm.$O\
 	net_loop.$O\
 	net_main.$O\
--- a/net.h
+++ b/net.h
@@ -1,102 +1,56 @@
-// net.h -- quake's interface to the networking layer
+typedef struct Addr Addr;
 
-struct qsockaddr
-{
-	short sa_family;
-	unsigned char sa_data[14];
+struct Addr{
+	int fd;
+	char ip[46];
+	char srv[6];
+	char sys[52];
 };
+extern Addr myip;
+extern char *netmtpt;
 
+enum{
+	NET_NAMELEN = 64,
+	NET_MAXMESSAGE = 8192,
+	NET_HEADERSIZE = 4 + 4,
+	NET_DATAGRAMSIZE = MAX_DATAGRAM + NET_HEADERSIZE,
 
-#define	NET_NAMELEN			64
+	/* netheader flags */
+	NFMASK	= 0xffff,
+	NFDAT	= 1<<16,
+	NFACK	= 1<<17,
+	NFNAK	= 1<<18,
+	NFEOM	= 1<<19,
+	NFUNREL	= 1<<20,
+	NFCTL	= 1<<31,
 
-#define NET_MAXMESSAGE		8192
-#define NET_HEADERSIZE		(2 * sizeof(unsigned int))
-#define NET_DATAGRAMSIZE	(MAX_DATAGRAM + NET_HEADERSIZE)
+	/* network info/connection protocol: used to find servers, get info
+	 * about them and connect to them. once connected, the game protocol is
+	 * used instead.
+	 * game[s]: always "QUAKE" for qk1. was supposed to allow this protocol
+	 * 	to be used in other games (hint: it never was)
+	 * v[1]: NETVERSION
+	 * addresses have two forms: "addr:port" and "port". the longer form is
+	 * used to return the address of a server which is not running locally.
+	 * the short form uses the address from which the request was made.
+	 */
+	NETVERSION = 3,
+	CQCONNECT = 1,		/* game[s] v[1] */
+	CQSVINFO  = 2,		/* game[s] v[1] */
+	CQPLINFO  = 3,		/* plnum[1] */
+	CQRUINFO  = 4,		/* rule[s] */
+	CPACCEPT  = 1<<7 | 1,	/* port[4] */
+	CPREJECT  = 1<<7 | 2,	/* reason[s] */
+	CPSVINFO  = 1<<7 | 3,
+	/* addr[s] host[s] map[s] curpl[1] maxpl[1] v[1] */
+	CPPLINFO  = 1<<7 | 4,
+	/* plnum[1] name[s] colors[4] frags[4] contime[4] addr[s] */
+	CPRUINFO  = 1<<7 | 5,	/* rule[s] val[s] */
 
-// NetHeader flags
-#define NETFLAG_LENGTH_MASK	0x0000ffff
-#define NETFLAG_DATA		0x00010000
-#define NETFLAG_ACK			0x00020000
-#define NETFLAG_NAK			0x00040000
-#define NETFLAG_EOM			0x00080000
-#define NETFLAG_UNRELIABLE	0x00100000
-#define NETFLAG_CTL			0x80000000
+	MAX_NET_DRIVERS = 8,
+	HOSTCACHESIZE = 8
+};
 
-
-#define NET_PROTOCOL_VERSION	3
-
-// This is the network info/connection protocol.  It is used to find Quake
-// servers, get info about them, and connect to them.  Once connected, the
-// Quake game protocol (documented elsewhere) is used.
-//
-//
-// General notes:
-//	game_name is currently always "QUAKE", but is there so this same protocol
-//		can be used for future games as well; can you say Quake2?
-//
-// CCREQ_CONNECT
-//		string	game_name				"QUAKE"
-//		byte	net_protocol_version	NET_PROTOCOL_VERSION
-//
-// CCREQ_SERVER_INFO
-//		string	game_name				"QUAKE"
-//		byte	net_protocol_version	NET_PROTOCOL_VERSION
-//
-// CCREQ_PLAYER_INFO
-//		byte	player_number
-//
-// CCREQ_RULE_INFO
-//		string	rule
-//
-//
-//
-// CCREP_ACCEPT
-//		long	port
-//
-// CCREP_REJECT
-//		string	reason
-//
-// CCREP_SERVER_INFO
-//		string	server_address
-//		string	host_name
-//		string	level_name
-//		byte	current_players
-//		byte	max_players
-//		byte	protocol_version	NET_PROTOCOL_VERSION
-//
-// CCREP_PLAYER_INFO
-//		byte	player_number
-//		string	name
-//		long	colors
-//		long	frags
-//		long	connect_time
-//		string	address
-//
-// CCREP_RULE_INFO
-//		string	rule
-//		string	value
-
-//	note:
-//		There are two address forms used above.  The short form is just a
-//		port number.  The address that goes along with the port is defined as
-//		"whatever address you receive this reponse from".  This lets us use
-//		the host OS to solve the problem of multiple host addresses (possibly
-//		with no routing between them); the host will use the right address
-//		when we reply to the inbound connection request.  The long from is
-//		a full address and port in a string.  It is used for returning the
-//		address of a server that is not running locally.
-
-#define CCREQ_CONNECT		0x01
-#define CCREQ_SERVER_INFO	0x02
-#define CCREQ_PLAYER_INFO	0x03
-#define CCREQ_RULE_INFO		0x04
-
-#define CCREP_ACCEPT		0x81
-#define CCREP_REJECT		0x82
-#define CCREP_SERVER_INFO	0x83
-#define CCREP_PLAYER_INFO	0x84
-#define CCREP_RULE_INFO		0x85
-
 typedef struct qsocket_s
 {
 	struct qsocket_s	*next;
@@ -124,9 +78,9 @@
 	int				receiveMessageLength;
 	byte			receiveMessage [NET_MAXMESSAGE];
 
-	struct qsockaddr	addr;
+	Addr addr;
+	int uready;
 	char				address[NET_NAMELEN];
-
 } qsocket_t;
 
 extern qsocket_t	*net_activeSockets;
@@ -133,60 +87,43 @@
 extern qsocket_t	*net_freeSockets;
 extern int			net_numsockets;
 
-typedef struct
-{
-	char		*name;
-	qboolean	initialized;
-	int			controlSock;
-	int			(*Init) (void);
-	void		(*Shutdown) (void);
-	void		(*Listen) (qboolean state);
-	int 		(*OpenSocket) (int port);
-	int 		(*CloseSocket) (int socket);
-	int 		(*Connect) (int socket, struct qsockaddr *addr);
-	int 		(*CheckNewConnections) (void);
-	int 		(*Read) (int socket, byte *buf, int len, struct qsockaddr *addr);
-	int 		(*Write) (int socket, byte *buf, int len, struct qsockaddr *addr);
-	int 		(*Broadcast) (int socket, byte *buf, int len);
-	char *		(*AddrToString) (struct qsockaddr *addr);
-	int 		(*StringToAddr) (char *string, struct qsockaddr *addr);
-	int 		(*GetSocketAddr) (int socket, struct qsockaddr *addr);
-	int 		(*GetNameFromAddr) (struct qsockaddr *addr, char *name);
-	int 		(*GetAddrFromName) (char *name, struct qsockaddr *addr);
-	int			(*AddrCompare) (struct qsockaddr *addr1, struct qsockaddr *addr2);
-	int			(*GetSocketPort) (struct qsockaddr *addr);
-	int			(*SetSocketPort) (struct qsockaddr *addr, int port);
-} net_landriver_t;
+typedef struct Landrv Landrv;
+typedef struct Netdrv Netdrv;
 
-#define	MAX_NET_DRIVERS		8
-extern int 				net_numlandrivers;
-extern net_landriver_t	net_landrivers[MAX_NET_DRIVERS];
+struct Landrv{
+	char *name;
+	qboolean initialized;
+	int	(*Init)(void);
+	void	(*Shutdown)(void);
+	int	(*Connect)(Addr *);
+	int	(*Read)(uchar *, int, Addr *);
+	int	(*Write)(uchar *, int, Addr *);
+	char*	(*AddrToString)(Addr *);
+	int	(*getip)(char *, Addr *);
+	int	(*AddrCompare)(Addr *, Addr *);
+	ushort	(*GetSocketPort)(Addr *);
+	void	(*SetSocketPort)(Addr *, ushort);
+};
+extern int net_numlandrivers;
+extern Landrv landrv[MAX_NET_DRIVERS];
 
-typedef struct
-{
-	char		*name;
-	qboolean	initialized;
-	int			(*Init) (void);
-	void		(*Listen) (qboolean state);
-	void		(*SearchForHosts) (qboolean xmit);
-	qsocket_t	*(*Connect) (char *host);
-	qsocket_t 	*(*CheckNewConnections) (void);
-	int			(*QGetMessage) (qsocket_t *sock);
-	int			(*QSendMessage) (qsocket_t *sock, sizebuf_t *data);
-	int			(*SendUnreliableMessage) (qsocket_t *sock, sizebuf_t *data);
-	qboolean	(*CanSendMessage) (qsocket_t *sock);
-	qboolean	(*CanSendUnreliableMessage) (qsocket_t *sock);
-	void		(*Close) (qsocket_t *sock);
-	void		(*Shutdown) (void);
-	int			controlSock;
-} net_driver_t;
+struct Netdrv{
+	char *name;
+	qboolean initialized;
+	int	(*Init)(void);
+	qsocket_t*	(*Connect)(char *);
+	qsocket_t*	(*CheckNewConnections)(void);
+	int	(*QGetMessage)(qsocket_t *);
+	int	(*QSendMessage)(qsocket_t *, sizebuf_t *);
+	int	(*SendUnreliableMessage)(qsocket_t *, sizebuf_t *);
+	qboolean	(*CanSendMessage)(qsocket_t *);
+	qboolean	(*CanSendUnreliableMessage)(qsocket_t *);
+	void	(*Close)(qsocket_t *);
+	void	(*Shutdown)(void);
+};
+extern int net_numdrivers;
+extern Netdrv netdrv[MAX_NET_DRIVERS];
 
-extern int			net_numdrivers;
-extern net_driver_t	net_drivers[MAX_NET_DRIVERS];
-
-extern int			DEFAULTnet_hostport;
-extern int			net_hostport;
-
 extern int net_driverlevel;
 extern cvar_t		hostname;
 extern char			playername[];
@@ -201,41 +138,6 @@
 void NET_FreeQSocket(qsocket_t *);
 double SetNetTime(void);
 
-
-#define HOSTCACHESIZE	8
-
-typedef struct
-{
-	char	name[16];
-	char	map[16];
-	char	cname[32];
-	int		users;
-	int		maxusers;
-	int		driver;
-	int		ldriver;
-	struct qsockaddr addr;
-} hostcache_t;
-
-extern int hostCacheCount;
-extern hostcache_t hostcache[HOSTCACHESIZE];
-
-#ifndef htonl
-extern u32int htonl (u32int hostlong);
-#endif
-#ifndef htons
-extern unsigned short htons (unsigned short hostshort);
-#endif
-#ifndef ntohl
-extern u32int ntohl (u32int netlong);
-#endif
-#ifndef ntohs
-extern unsigned short ntohs (unsigned short netshort);
-#endif
-
-#ifdef IDGODS
-qboolean IsID(struct qsockaddr *addr);
-#endif
-
 //============================================================================
 //
 // public network functions
@@ -286,39 +188,8 @@
 // from a server.
 // A netcon_t number will not be reused until this function is called for it
 
-void NET_Poll(void);
-
-
-typedef struct _PollProcedure
-{
-	struct _PollProcedure	*next;
-	double					nextTime;
-	void					(*procedure)(void *);
-	void					*arg;
-} PollProcedure;
-
-void SchedulePollProcedure(PollProcedure *pp, double timeOffset);
-
-extern	qboolean	serialAvailable;
-extern	qboolean	ipxAvailable;
-extern	qboolean	tcpipAvailable;
-extern	char		my_ipx_address[NET_NAMELEN];
-extern	char		my_tcpip_address[NET_NAMELEN];
-extern void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
-extern void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
-extern void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
-extern void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
-
-extern	qboolean	slistInProgress;
-extern	qboolean	slistSilent;
-extern	qboolean	slistLocal;
-
-void NET_Slist_f (void);
-
-/* dgrm */
 int			Datagram_Init (void);
 void		Datagram_Listen (qboolean state);
-void		Datagram_SearchForHosts (qboolean xmit);
 qsocket_t	*Datagram_Connect (char *host);
 qsocket_t 	*Datagram_CheckNewConnections (void);
 int			Datagram_GetMessage (qsocket_t *sock);
@@ -326,13 +197,11 @@
 int			Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
 qboolean	Datagram_CanSendMessage (qsocket_t *sock);
 qboolean	Datagram_CanSendUnreliableMessage (qsocket_t *sock);
-void		Datagram_Close (qsocket_t *sock);
+void	Datagram_Close(qsocket_t *);
 void		Datagram_Shutdown (void);
 
-/* loop */
 int			Loop_Init (void);
 void		Loop_Listen (qboolean state);
-void		Loop_SearchForHosts (qboolean xmit);
 qsocket_t 	*Loop_Connect (char *host);
 qsocket_t 	*Loop_CheckNewConnections (void);
 int			Loop_GetMessage (qsocket_t *sock);
@@ -343,22 +212,16 @@
 void		Loop_Close (qsocket_t *sock);
 void		Loop_Shutdown (void);
 
-/* udp */
-int  UDP_Init (void);
-void UDP_Shutdown (void);
-void UDP_Listen (qboolean state);
-int  UDP_OpenSocket (int port);
-int  UDP_CloseSocket (int socket);
-int  UDP_Connect (int socket, struct qsockaddr *addr);
-int  UDP_CheckNewConnections (void);
-int  UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr);
-int  UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr);
-int  UDP_Broadcast (int socket, byte *buf, int len);
-char *UDP_AddrToString (struct qsockaddr *addr);
-int  UDP_StringToAddr (char *string, struct qsockaddr *addr);
-int  UDP_GetSocketAddr (int socket, struct qsockaddr *addr);
-int  UDP_GetNameFromAddr (struct qsockaddr *addr, char *name);
-int  UDP_GetAddrFromName (char *name, struct qsockaddr *addr);
-int  UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
-int  UDP_GetSocketPort (struct qsockaddr *addr);
-int  UDP_SetSocketPort (struct qsockaddr *addr, int port);
+int	UDP_Init(void);
+void	UDP_Shutdown(void);
+void	UDP_Listen(qboolean);
+int	UDP_Connect(Addr *);
+int	udpread(uchar *, int, Addr *);
+int	udpwrite(uchar *, int, Addr *);
+void	udpinfo(Addr*);
+int	getnewcon(Addr*);
+char*	UDP_AddrToString(Addr *);
+int	getip(char *, Addr *);
+int	UDP_AddrCompare(Addr *, Addr *);
+ushort	UDP_GetSocketPort(Addr *);
+void	UDP_SetSocketPort(Addr *, ushort);
--- a/net_bsd.c
+++ /dev/null
@@ -1,73 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include "dat.h"
-#include "quakedef.h"
-#include "fns.h"
-
-net_driver_t net_drivers[MAX_NET_DRIVERS] =
-{
-	{
-	"Loopback",
-	false,
-	Loop_Init,
-	Loop_Listen,
-	Loop_SearchForHosts,
-	Loop_Connect,
-	Loop_CheckNewConnections,
-	Loop_GetMessage,
-	Loop_SendMessage,
-	Loop_SendUnreliableMessage,
-	Loop_CanSendMessage,
-	Loop_CanSendUnreliableMessage,
-	Loop_Close,
-	Loop_Shutdown
-	}
-	,
-	{
-	"Datagram",
-	false,
-	Datagram_Init,
-	Datagram_Listen,
-	Datagram_SearchForHosts,
-	Datagram_Connect,
-	Datagram_CheckNewConnections,
-	Datagram_GetMessage,
-	Datagram_SendMessage,
-	Datagram_SendUnreliableMessage,
-	Datagram_CanSendMessage,
-	Datagram_CanSendUnreliableMessage,
-	Datagram_Close,
-	Datagram_Shutdown
-	}
-};
-
-int net_numdrivers = 2;
-
-net_landriver_t	net_landrivers[MAX_NET_DRIVERS] =
-{
-	{
-	"UDP",
-	false,
-	0,
-	UDP_Init,
-	UDP_Shutdown,
-	UDP_Listen,
-	UDP_OpenSocket,
-	UDP_CloseSocket,
-	UDP_Connect,
-	UDP_CheckNewConnections,
-	UDP_Read,
-	UDP_Write,
-	UDP_Broadcast,
-	UDP_AddrToString,
-	UDP_StringToAddr,
-	UDP_GetSocketAddr,
-	UDP_GetNameFromAddr,
-	UDP_GetAddrFromName,
-	UDP_AddrCompare,
-	UDP_GetSocketPort,
-	UDP_SetSocketPort
-	}
-};
-
-int net_numlandrivers = 1;
--- a/net_dgrm.c
+++ b/net_dgrm.c
@@ -1,58 +1,29 @@
 #include <u.h>
 #include <libc.h>
+#include <ip.h>
 #include "dat.h"
 #include "quakedef.h"
 #include "fns.h"
 
-// This is enables a simple IP banning mechanism
-//#define BAN_TEST	/* FIXME */
+//#define DEBUG
 
-#ifdef BAN_TEST
-#define AF_INET 		2	/* internet */
-struct in_addr
-{
-	union
-	{
-		struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b;
-		struct { unsigned short s_w1,s_w2; } S_un_w;
-		u32int S_addr;
-	} S_un;
-};
-#define	s_addr	S_un.S_addr	/* can be used for most tcp & ip code */
-struct sockaddr_in
-{
-    short			sin_family;
-    unsigned short	sin_port;
-	struct in_addr	sin_addr;
-    char			sin_zero[8];
-};
-char *inet_ntoa(struct in_addr in);
-u32int inet_addr(const char *cp);
-#endif	// BAN_TEST
-
-
 // these two macros are to make the code more readable
-#define sfunc	net_landrivers[sock->landriver]
-#define dfunc	net_landrivers[net_landriverlevel]
+#define sfunc	landrv[sock->landriver]
+#define dfunc	landrv[net_landriverlevel]
 
 static int net_landriverlevel;
 
 /* statistic counters */
-int	packetsSent = 0;
-int	packetsReSent = 0;
-int packetsReceived = 0;
-int receivedDuplicateCount = 0;
-int shortPacketCount = 0;
+int packetsSent;
+int packetsReSent;
+int packetsReceived;
+int receivedDuplicateCount;
+int shortPacketCount;
 int droppedDatagrams;
 
 static int myDriverLevel;
 
-struct
-{
-	unsigned int	length;
-	unsigned int	sequence;
-	byte			data[MAX_DATAGRAM];
-} packetBuffer;
+static uchar netbuf[4+4+NET_MAXMESSAGE];
 
 extern int m_return_state;
 extern int m_state;
@@ -59,85 +30,19 @@
 extern qboolean m_return_onerror;
 extern char m_return_reason[32];
 
-
-#ifdef DEBUG
-char *StrAddr (struct qsockaddr *addr)
+static int
+netpack(Addr *a, int f, uint seq, uchar *buf, int n)
 {
-	static char buf[34];
-	byte *p = (byte *)addr;
-	int n;
-
-	for (n = 0; n < 16; n++)
-		sprint (buf + n * 2, "%02x", *p++);
-	return buf;
+	hnputl(netbuf, NET_HEADERSIZE + n | f);
+	hnputl(netbuf+4, seq);
+	if(buf != nil)
+		memcpy(netbuf+8, buf, n);
+	return udpwrite(netbuf, NET_HEADERSIZE + n, a);
 }
-#endif
 
-
-#ifdef BAN_TEST
-u32int banAddr = 0x00000000;
-u32int banMask = 0xffffffff;
-
-void NET_Ban_f (void)
+int Datagram_SendMessage (qsocket_t *s, sizebuf_t *data)
 {
-	char	addrStr [32];
-	char	maskStr [32];
-	void	(*print) (char *fmt, ...);
-
-	if (cmd_source == src_command)
-	{
-		if (!sv.active)
-		{
-			Cmd_ForwardToServer ();
-			return;
-		}
-		print = Con_Printf;
-	}
-	else
-	{
-		if (pr_global_struct->deathmatch && !host_client->privileged)
-			return;
-		print = SV_ClientPrintf;
-	}
-
-	switch (Cmd_Argc ())
-	{
-		case 1:
-			if (((struct in_addr *)&banAddr)->s_addr)
-			{
-				strcpy(addrStr, inet_ntoa(*(struct in_addr *)&banAddr));
-				strcpy(maskStr, inet_ntoa(*(struct in_addr *)&banMask));
-				print("Banning %s [%s]\n", addrStr, maskStr);
-			}
-			else
-				print("Banning not active\n");
-			break;
-
-		case 2:
-			if(cistrcmp(Cmd_Argv(1), "off") == 0)
-				banAddr = 0x00000000;
-			else
-				banAddr = inet_addr(Cmd_Argv(1));
-			banMask = 0xffffffff;
-			break;
-
-		case 3:
-			banAddr = inet_addr(Cmd_Argv(1));
-			banMask = inet_addr(Cmd_Argv(2));
-			break;
-
-		default:
-			print("BAN ip_address [mask]\n");
-			break;
-	}
-}
-#endif // BAN_TEST
-
-
-int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data)
-{
-	unsigned int	packetLen;
-	unsigned int	dataLen;
+	unsigned int	n;
 	unsigned int	eom;
 
 #ifdef DEBUG
@@ -147,101 +52,68 @@
 	if (data->cursize > NET_MAXMESSAGE)
 		fatal("Datagram_SendMessage: message too big %ud\n", data->cursize);
 
-	if (sock->canSend == false)
+	if (s->canSend == false)
 		fatal("SendMessage: called with canSend == false\n");
 #endif
 
-	memcpy(sock->sendMessage, data->data, data->cursize);
-	sock->sendMessageLength = data->cursize;
-
-	if (data->cursize <= MAX_DATAGRAM)
-	{
-		dataLen = data->cursize;
-		eom = NETFLAG_EOM;
-	}
-	else
-	{
-		dataLen = MAX_DATAGRAM;
+	memcpy(s->sendMessage, data->data, data->cursize);
+	s->sendMessageLength = data->cursize;
+	if(data->cursize <= MAX_DATAGRAM){
+		n = data->cursize;
+		eom = NFEOM;
+	}else{
+		n = MAX_DATAGRAM;
 		eom = 0;
 	}
-	packetLen = NET_HEADERSIZE + dataLen;
-
-	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
-	packetBuffer.sequence = BigLong(sock->sendSequence++);
-	memcpy(packetBuffer.data, sock->sendMessage, dataLen);
-
-	sock->canSend = false;
-
-	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
+	s->canSend = false;
+	if(netpack(&s->addr, NFDAT|eom, s->sendSequence++, s->sendMessage, n) < 0)
 		return -1;
-
-	sock->lastSendTime = net_time;
+	s->lastSendTime = net_time;
 	packetsSent++;
 	return 1;
 }
 
 
-int SendMessageNext (qsocket_t *sock)
+int SendMessageNext (qsocket_t *s)
 {
-	unsigned int	packetLen;
-	unsigned int	dataLen;
+	unsigned int	n;
 	unsigned int	eom;
 
-	if (sock->sendMessageLength <= MAX_DATAGRAM)
-	{
-		dataLen = sock->sendMessageLength;
-		eom = NETFLAG_EOM;
-	}
-	else
-	{
-		dataLen = MAX_DATAGRAM;
+	if(s->sendMessageLength <= MAX_DATAGRAM){
+		n = s->sendMessageLength;
+		eom = NFEOM;
+	}else{
+		n = MAX_DATAGRAM;
 		eom = 0;
 	}
-	packetLen = NET_HEADERSIZE + dataLen;
-
-	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
-	packetBuffer.sequence = BigLong(sock->sendSequence++);
-	memcpy(packetBuffer.data, sock->sendMessage, dataLen);
-
-	sock->sendNext = false;
-
-	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
+	s->sendNext = false;
+	if(netpack(&s->addr, NFDAT|eom, s->sendSequence++, s->sendMessage, n) < 0)
 		return -1;
-
-	sock->lastSendTime = net_time;
+	s->lastSendTime = net_time;
 	packetsSent++;
 	return 1;
 }
 
 
-int ReSendMessage (qsocket_t *sock)
+int ReSendMessage (qsocket_t *s)
 {
-	unsigned int	packetLen;
-	unsigned int	dataLen;
+	unsigned int	n;
 	unsigned int	eom;
 
-	if (sock->sendMessageLength <= MAX_DATAGRAM)
+	if (s->sendMessageLength <= MAX_DATAGRAM)
 	{
-		dataLen = sock->sendMessageLength;
-		eom = NETFLAG_EOM;
+		n = s->sendMessageLength;
+		eom = NFEOM;
 	}
 	else
 	{
-		dataLen = MAX_DATAGRAM;
+		n = MAX_DATAGRAM;
 		eom = 0;
 	}
-	packetLen = NET_HEADERSIZE + dataLen;
-
-	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
-	packetBuffer.sequence = BigLong(sock->sendSequence - 1);
-	memcpy(packetBuffer.data, sock->sendMessage, dataLen);
-
-	sock->sendNext = false;
-
-	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
+	s->sendNext = false;
+	if(netpack(&s->addr, NFDAT|eom, s->sendSequence-1, s->sendMessage, n) < 0)
 		return -1;
-
-	sock->lastSendTime = net_time;
+	s->lastSendTime = net_time;
 	packetsReSent++;
 	return 1;
 }
@@ -256,16 +128,14 @@
 }
 
 
-qboolean Datagram_CanSendUnreliableMessage (qsocket_t *) /*sock*/
+qboolean Datagram_CanSendUnreliableMessage (qsocket_t *)
 {
 	return true;
 }
 
 
-int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
+int Datagram_SendUnreliableMessage (qsocket_t *s, sizebuf_t *data)
 {
-	int 	packetLen;
-
 #ifdef DEBUG
 	if (data->cursize == 0)
 		fatal("Datagram_SendUnreliableMessage: zero length message\n");
@@ -274,15 +144,8 @@
 		fatal("Datagram_SendUnreliableMessage: message too big %ud\n", data->cursize);
 #endif
 
-	packetLen = NET_HEADERSIZE + data->cursize;
-
-	packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE);
-	packetBuffer.sequence = BigLong(sock->unreliableSendSequence++);
-	memcpy(packetBuffer.data, data->data, data->cursize);
-
-	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
+	if(netpack(&s->addr, NFUNREL, s->unreliableSendSequence++, data->data, data->cursize) < 0)
 		return -1;
-
 	packetsSent++;
 	return 1;
 }
@@ -290,10 +153,9 @@
 
 int	Datagram_GetMessage (qsocket_t *sock)
 {
-	unsigned int	length;
+	int n;
 	unsigned int	flags;
 	int				ret = 0;
-	struct qsockaddr readaddr;
 	unsigned int	sequence;
 	unsigned int	count;
 
@@ -300,50 +162,34 @@
 	if (!sock->canSend)
 		if ((net_time - sock->lastSendTime) > 1.0)
 			ReSendMessage (sock);
-
 	while(1)
-	{	
-		length = sfunc.Read (sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);
-
-//	if ((rand() & 255) > 220)
-//		continue;
-
-		if (length == 0)
+	{
+		if((n = udpread(netbuf, NET_MAXMESSAGE, &sock->addr)) == 0)
 			break;
 
-		if (length == -1)
+		if (n == -1)
 		{
 			Con_Printf("Read error\n");
 			return -1;
 		}
 
-		if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0)
+		if (n < NET_HEADERSIZE)
 		{
-#ifdef DEBUG
-			fprint(2, "Datagram_GetMessage: forged pkt received\n"
-				"%s instead of %s\n",
-				StrAddr(&readaddr), StrAddr(&sock->addr));
-#endif
-			continue;
-		}
-
-		if (length < NET_HEADERSIZE)
-		{
 			shortPacketCount++;
 			continue;
 		}
 
-		length = BigLong(packetBuffer.length);
-		flags = length & (~NETFLAG_LENGTH_MASK);
-		length &= NETFLAG_LENGTH_MASK;
+		n = nhgetl(netbuf);
+		flags = n & (~NFMASK);
+		n &= NFMASK;
 
-		if (flags & NETFLAG_CTL)
+		if (flags & NFCTL)
 			continue;
 
-		sequence = BigLong(packetBuffer.sequence);
+		sequence = nhgetl(netbuf+4);
 		packetsReceived++;
 
-		if (flags & NETFLAG_UNRELIABLE)
+		if (flags & NFUNREL)
 		{
 			if (sequence < sock->unreliableReceiveSequence)
 			{
@@ -359,16 +205,16 @@
 			}
 			sock->unreliableReceiveSequence = sequence + 1;
 
-			length -= NET_HEADERSIZE;
+			n -= NET_HEADERSIZE;
 
 			SZ_Clear (&net_message);
-			SZ_Write (&net_message, packetBuffer.data, length);
+			SZ_Write (&net_message, netbuf+8, n);
 
 			ret = 2;
 			break;
 		}
 
-		if (flags & NETFLAG_ACK)
+		if (flags & NFACK)
 		{
 			if (sequence != (sock->sendSequence - 1))
 			{
@@ -400,12 +246,9 @@
 			continue;
 		}
 
-		if (flags & NETFLAG_DATA)
+		if (flags & NFDAT)
 		{
-			packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);
-			packetBuffer.sequence = BigLong(sequence);
-			sfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr);
-
+			netpack(&sock->addr, NFACK, sequence, nil, 0);
 			if (sequence != sock->receiveSequence)
 			{
 				receivedDuplicateCount++;
@@ -413,13 +256,13 @@
 			}
 			sock->receiveSequence++;
 
-			length -= NET_HEADERSIZE;
+			n -= NET_HEADERSIZE;
 
-			if (flags & NETFLAG_EOM)
+			if (flags & NFEOM)
 			{
 				SZ_Clear(&net_message);
 				SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);
-				SZ_Write(&net_message, packetBuffer.data, length);
+				SZ_Write(&net_message, netbuf+8, n);
 				sock->receiveMessageLength = 0;
 
 				ret = 1;
@@ -426,8 +269,8 @@
 				break;
 			}
 
-			memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);
-			sock->receiveMessageLength += length;
+			memcpy(sock->receiveMessage + sock->receiveMessageLength, netbuf+8, n);
+			sock->receiveMessageLength += n;
 			continue;
 		}
 	}
@@ -486,281 +329,20 @@
 	}
 }
 
-
-static qboolean testInProgress = false;
-static int		testPollCount;
-static int		testDriver;
-static int		testSocket;
-
-static void Test_Poll(void *);
-PollProcedure	testPollProcedure = {nil, 0.0, Test_Poll};
-
-static void Test_Poll(void *)
+int
+Datagram_Init(void)
 {
-	struct qsockaddr clientaddr;
-	int		control;
-	int		len;
-	char	name[32];
-	char	address[64];
-	int		colors;
-	int		frags;
-	int		connectTime;
-
-	net_landriverlevel = testDriver;
-
-	while (1)
-	{
-		len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr);
-		if (len < sizeof(int))
-			break;
-
-		net_message.cursize = len;
-
-		MSG_BeginReading ();
-		control = BigLong(*((int *)net_message.data));
-		MSG_ReadLong();
-		if (control == -1)
-			break;
-		if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
-			break;
-		if ((control & NETFLAG_LENGTH_MASK) != len)
-			break;
-
-		if (MSG_ReadByte() != CCREP_PLAYER_INFO)
-			fatal("Unexpected repsonse to Player Info request\n");
-
-		MSG_ReadByte();	/* playerNumber */
-		strcpy(name, MSG_ReadString());
-		colors = MSG_ReadLong();
-		frags = MSG_ReadLong();
-		connectTime = MSG_ReadLong();
-		strcpy(address, MSG_ReadString());
-
-		Con_Printf("%s\n  frags:%3d  colors:%ud %ud  time:%ud\n  %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address);
-	}
-
-	testPollCount--;
-	if (testPollCount)
-	{
-		SchedulePollProcedure(&testPollProcedure, 0.1);
-	}
-	else
-	{
-		dfunc.CloseSocket(testSocket);
-		testInProgress = false;
-	}
-}
-
-static void Test_f (void)
-{
-	char	*host;
-	int		n;
-	int		max = MAX_SCOREBOARD;
-	struct qsockaddr sendaddr;
-
-	if (testInProgress)
-		return;
-
-	host = Cmd_Argv (1);
-
-	if (host && hostCacheCount)
-	{
-		for (n = 0; n < hostCacheCount; n++)
-			if(cistrcmp(host, hostcache[n].name) == 0)
-			{
-				if (hostcache[n].driver != myDriverLevel)
-					continue;
-				net_landriverlevel = hostcache[n].ldriver;
-				max = hostcache[n].maxusers;
-				memcpy(&sendaddr, &hostcache[n].addr, sizeof sendaddr);
-				break;
-			}
-		if (n < hostCacheCount)
-			goto JustDoIt;
-	}
-
-	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-	{
-		if (!net_landrivers[net_landriverlevel].initialized)
-			continue;
-
-		// see if we can resolve the host name
-		if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
-			break;
-	}
-	if (net_landriverlevel == net_numlandrivers)
-		return;
-
-JustDoIt:
-	testSocket = dfunc.OpenSocket(0);
-	if (testSocket == -1)
-		return;
-
-	testInProgress = true;
-	testPollCount = 20;
-	testDriver = net_landriverlevel;
-
-	for (n = 0; n < max; n++)
-	{
-		SZ_Clear(&net_message);
-		// save space for the header, filled in later
-		MSG_WriteLong(&net_message, 0);
-		MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO);
-		MSG_WriteByte(&net_message, n);
-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | 	(net_message.cursize & NETFLAG_LENGTH_MASK));
-		dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr);
-	}
-	SZ_Clear(&net_message);
-	SchedulePollProcedure(&testPollProcedure, 0.1);
-}
-
-
-static qboolean test2InProgress = false;
-static int		test2Driver;
-static int		test2Socket;
-
-static void Test2_Poll(void *);
-PollProcedure	test2PollProcedure = {nil, 0.0, Test2_Poll};
-
-static void Test2_Poll(void *)
-{
-	struct qsockaddr clientaddr;
-	int		control;
-	int		len;
-	char	name[256];
-	char	value[256];
-
-	net_landriverlevel = test2Driver;
-	name[0] = 0;
-
-	len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr);
-	if (len < sizeof(int))
-		goto Reschedule;
-
-	net_message.cursize = len;
-
-	MSG_BeginReading ();
-	control = BigLong(*((int *)net_message.data));
-	MSG_ReadLong();
-	if (control == -1)
-		goto Error;
-	if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
-		goto Error;
-	if ((control & NETFLAG_LENGTH_MASK) != len)
-		goto Error;
-
-	if (MSG_ReadByte() != CCREP_RULE_INFO)
-		goto Error;
-
-	strcpy(name, MSG_ReadString());
-	if (name[0] == 0)
-		goto Done;
-	strcpy(value, MSG_ReadString());
-
-	Con_Printf("%-16.16s  %-16.16s\n", name, value);
-
-	SZ_Clear(&net_message);
-	// save space for the header, filled in later
-	MSG_WriteLong(&net_message, 0);
-	MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
-	MSG_WriteString(&net_message, name);
-	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-	dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr);
-	SZ_Clear(&net_message);
-
-Reschedule:
-	SchedulePollProcedure(&test2PollProcedure, 0.05);
-	return;
-
-Error:
-	Con_Printf("Unexpected repsonse to Rule Info request\n");
-Done:
-	dfunc.CloseSocket(test2Socket);
-	test2InProgress = false;
-	return;
-}
-
-static void Test2_f (void)
-{
-	char	*host;
-	int		n;
-	struct qsockaddr sendaddr;
-
-	if (test2InProgress)
-		return;
-
-	host = Cmd_Argv (1);
-
-	if (host && hostCacheCount)
-	{
-		for (n = 0; n < hostCacheCount; n++)
-			if(cistrcmp(host, hostcache[n].name) == 0)
-			{
-				if (hostcache[n].driver != myDriverLevel)
-					continue;
-				net_landriverlevel = hostcache[n].ldriver;
-				memcpy(&sendaddr, &hostcache[n].addr, sizeof sendaddr);
-				break;
-			}
-		if (n < hostCacheCount)
-			goto JustDoIt;
-	}
-
-	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-	{
-		if (!net_landrivers[net_landriverlevel].initialized)
-			continue;
-
-		// see if we can resolve the host name
-		if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
-			break;
-	}
-	if (net_landriverlevel == net_numlandrivers)
-		return;
-
-JustDoIt:
-	test2Socket = dfunc.OpenSocket(0);
-	if (test2Socket == -1)
-		return;
-
-	test2InProgress = true;
-	test2Driver = net_landriverlevel;
-
-	SZ_Clear(&net_message);
-	// save space for the header, filled in later
-	MSG_WriteLong(&net_message, 0);
-	MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
-	MSG_WriteString(&net_message, "");
-	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-	dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr);
-	SZ_Clear(&net_message);
-	SchedulePollProcedure(&test2PollProcedure, 0.05);
-}
-
-
-int Datagram_Init (void)
-{
 	int i;
-	int csock;
 
 	myDriverLevel = net_driverlevel;
-	Cmd_AddCommand ("net_stats", NET_Stats_f);
+	Cmd_AddCommand("net_stats", NET_Stats_f);
 
-	for (i = 0; i < net_numlandrivers; i++)
-		{
-		csock = net_landrivers[i].Init ();
-		if (csock == -1)
+	for(i=0; i<net_numlandrivers; i++){
+		if(landrv[i].Init() < 0)
 			continue;
-		net_landrivers[i].initialized = true;
-		net_landrivers[i].controlSock = csock;
-		}
+		landrv[i].initialized = true;
+	}
 
-#ifdef BAN_TEST
-	Cmd_AddCommand ("ban", NET_Ban_f);
-#endif
-	Cmd_AddCommand ("test", Test_f);
-	Cmd_AddCommand ("test2", Test2_f);
-
 	return 0;
 }
 
@@ -774,53 +356,31 @@
 //
 	for (i = 0; i < net_numlandrivers; i++)
 	{
-		if (net_landrivers[i].initialized)
+		if (landrv[i].initialized)
 		{
-			net_landrivers[i].Shutdown ();
-			net_landrivers[i].initialized = false;
+			landrv[i].Shutdown ();
+			landrv[i].initialized = false;
 		}
 	}
 }
 
-
-void Datagram_Close (qsocket_t *sock)
-{
-	sfunc.CloseSocket(sock->socket);
-}
-
-
-void Datagram_Listen (qboolean state)
-{
-	int i;
-
-	for (i = 0; i < net_numlandrivers; i++)
-		if (net_landrivers[i].initialized)
-			net_landrivers[i].Listen (state);
-}
-
-
 static qsocket_t *_Datagram_CheckNewConnections (void)
 {
-	struct qsockaddr clientaddr;
-	struct qsockaddr newaddr;
+	Addr clientaddr;
 	int			newsock;
-	int			acceptsock;
 	qsocket_t	*sock;
 	qsocket_t	*s;
 	int			len;
 	int			command;
 	int			control;
-	int			ret;
 
-	acceptsock = dfunc.CheckNewConnections();
-	if (acceptsock == -1)
+	memset(&clientaddr, 0, sizeof clientaddr);
+	if(getnewcon(&clientaddr) == 0)
 		return nil;
-
 	SZ_Clear(&net_message);
-
-	len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);
-	if (len < sizeof(int))
-		return nil;
+	len = udpread(net_message.data, net_message.maxsize, &clientaddr);
+	if (len < sizeof(s32int))
+		goto done;
 	net_message.cursize = len;
 
 	MSG_BeginReading ();
@@ -827,36 +387,34 @@
 	control = BigLong(*((int *)net_message.data));
 	MSG_ReadLong();
 	if (control == -1)
-		return nil;
-	if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
-		return nil;
-	if ((control & NETFLAG_LENGTH_MASK) != len)
-		return nil;
+		goto done;
+	if ((control & (~NFMASK)) !=  NFCTL)
+		goto done;
+	if ((control & NFMASK) != len)
+		goto done;
 
 	command = MSG_ReadByte();
-	if (command == CCREQ_SERVER_INFO)
+	if (command == CQSVINFO)
 	{
 		if(strcmp(MSG_ReadString(), "QUAKE") != 0)
-			return nil;
-
+			goto done;
 		SZ_Clear(&net_message);
 		// save space for the header, filled in later
 		MSG_WriteLong(&net_message, 0);
-		MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
-		dfunc.GetSocketAddr(acceptsock, &newaddr);
-		MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
+		MSG_WriteByte(&net_message, CPSVINFO);
+		MSG_WriteString(&net_message, dfunc.AddrToString(&myip));
 		MSG_WriteString(&net_message, hostname.string);
 		MSG_WriteString(&net_message, sv.name);
 		MSG_WriteByte(&net_message, net_activeconnections);
 		MSG_WriteByte(&net_message, svs.maxclients);
-		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+		MSG_WriteByte(&net_message, NETVERSION);
+		*((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+		dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
 		SZ_Clear(&net_message);
-		return nil;
+		goto done;
 	}
 
-	if (command == CCREQ_PLAYER_INFO)
+	if (command == CQPLINFO)
 	{
 		int			playerNumber;
 		int			activeNumber;
@@ -875,12 +433,12 @@
 			}
 		}
 		if (clientNumber == svs.maxclients)
-			return nil;
+			goto done;
 
 		SZ_Clear(&net_message);
 		// save space for the header, filled in later
 		MSG_WriteLong(&net_message, 0);
-		MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);
+		MSG_WriteByte(&net_message, CPPLINFO);
 		MSG_WriteByte(&net_message, playerNumber);
 		MSG_WriteString(&net_message, client->name);
 		MSG_WriteLong(&net_message, client->colors);
@@ -887,14 +445,14 @@
 		MSG_WriteLong(&net_message, (int)client->edict->v.frags);
 		MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
 		MSG_WriteString(&net_message, client->netconnection->address);
-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+		*((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+		dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
 		SZ_Clear(&net_message);
 
-		return nil;
+		goto done;
 	}
 
-	if (command == CCREQ_RULE_INFO)
+	if (command == CQRUINFO)
 	{
 		char	*prevCvarName;
 		cvar_t	*var;
@@ -905,7 +463,7 @@
 		{
 			var = Cvar_FindVar (prevCvarName);
 			if (!var)
-				return nil;
+				goto done;
 			var = var->next;
 		}
 		else
@@ -924,89 +482,66 @@
 		SZ_Clear(&net_message);
 		// save space for the header, filled in later
 		MSG_WriteLong(&net_message, 0);
-		MSG_WriteByte(&net_message, CCREP_RULE_INFO);
+		MSG_WriteByte(&net_message, CPRUINFO);
 		if (var)
 		{
 			MSG_WriteString(&net_message, var->name);
 			MSG_WriteString(&net_message, var->string);
 		}
-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+		*((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+		dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
 		SZ_Clear(&net_message);
 
-		return nil;
+		goto done;
 	}
 
-	if (command != CCREQ_CONNECT)
-		return nil;
+	if (command != CQCONNECT)
+		goto done;
 
 	if(strcmp(MSG_ReadString(), "QUAKE") != 0)
-		return nil;
+		goto done;
 
-	if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
+	if (MSG_ReadByte() != NETVERSION)
 	{
 		SZ_Clear(&net_message);
 		// save space for the header, filled in later
 		MSG_WriteLong(&net_message, 0);
-		MSG_WriteByte(&net_message, CCREP_REJECT);
+		MSG_WriteByte(&net_message, CPREJECT);
 		MSG_WriteString(&net_message, "Incompatible version.\n");
-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+		*((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+		dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
 		SZ_Clear(&net_message);
-		return nil;
+		goto done;
 	}
 
-#ifdef BAN_TEST
-	// check for a ban
-	if (clientaddr.sa_family == AF_INET)
+	// see if this guy is already connected
+	for (s = net_activeSockets; s; s = s->next)
 	{
-		u32int testAddr;
-		testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr;
-		if ((testAddr & banMask) == banAddr)
+		if (s->driver != net_driverlevel)
+			continue;
+		if(strcmp(clientaddr.ip, s->addr.ip) != 0 || strcmp(clientaddr.srv, s->addr.srv) != 0)
+			continue;
+		// is this a duplicate connection reqeust?
+		if(strcmp(clientaddr.srv, s->addr.srv) == 0
+		&& net_time - s->connecttime < 2.0)
 		{
+			// yes, so send a duplicate reply
 			SZ_Clear(&net_message);
 			// save space for the header, filled in later
 			MSG_WriteLong(&net_message, 0);
-			MSG_WriteByte(&net_message, CCREP_REJECT);
-			MSG_WriteString(&net_message, "You have been banned.\n");
-			*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-			dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+			MSG_WriteByte(&net_message, CPACCEPT);
+			MSG_WriteLong(&net_message, dfunc.GetSocketPort(&myip));
+			*((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+			dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
 			SZ_Clear(&net_message);
-			return nil;
+			goto done;
 		}
+		// it's somebody coming back in from a crash/disconnect
+		// so close the old qsocket and let their retry get them back in
+		NET_Close(s);
+		goto done;
 	}
-#endif
 
-	// see if this guy is already connected
-	for (s = net_activeSockets; s; s = s->next)
-	{
-		if (s->driver != net_driverlevel)
-			continue;
-		ret = dfunc.AddrCompare(&clientaddr, &s->addr);
-		if (ret >= 0)
-		{
-			// is this a duplicate connection reqeust?
-			if (ret == 0 && net_time - s->connecttime < 2.0)
-			{
-				// yes, so send a duplicate reply
-				SZ_Clear(&net_message);
-				// save space for the header, filled in later
-				MSG_WriteLong(&net_message, 0);
-				MSG_WriteByte(&net_message, CCREP_ACCEPT);
-				dfunc.GetSocketAddr(s->socket, &newaddr);
-				MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
-				*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-				dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
-				SZ_Clear(&net_message);
-				return nil;
-			}
-			// it's somebody coming back in from a crash/disconnect
-			// so close the old qsocket and let their retry get them back in
-			NET_Close(s);
-			return nil;
-		}
-	}
-
 	// allocate a QSocket
 	sock = NET_NewQSocket ();
 	if (sock == nil)
@@ -1015,49 +550,37 @@
 		SZ_Clear(&net_message);
 		// save space for the header, filled in later
 		MSG_WriteLong(&net_message, 0);
-		MSG_WriteByte(&net_message, CCREP_REJECT);
+		MSG_WriteByte(&net_message, CPREJECT);
 		MSG_WriteString(&net_message, "Server is full.\n");
-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+		*((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+		dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
 		SZ_Clear(&net_message);
-		return nil;
+		goto done;
 	}
 
 	// allocate a network socket
-	newsock = dfunc.OpenSocket(0);
-	if (newsock == -1)
-	{
-		NET_FreeQSocket(sock);
-		return nil;
-	}
+	newsock = 1;
 
-	// connect to the client
-	if (dfunc.Connect (newsock, &clientaddr) == -1)
-	{
-		dfunc.CloseSocket(newsock);
-		NET_FreeQSocket(sock);
-		return nil;
-	}
-
 	// everything is allocated, just fill in the details	
 	sock->socket = newsock;
 	sock->landriver = net_landriverlevel;
-	sock->addr = clientaddr;
-	strcpy(sock->address, dfunc.AddrToString(&clientaddr));
+	memcpy(&sock->addr, &clientaddr, sizeof clientaddr);
+	strcpy(sock->address, UDP_AddrToString(&clientaddr));
 
 	// send him back the info about the server connection he has been allocated
 	SZ_Clear(&net_message);
 	// save space for the header, filled in later
 	MSG_WriteLong(&net_message, 0);
-	MSG_WriteByte(&net_message, CCREP_ACCEPT);
-	dfunc.GetSocketAddr(newsock, &newaddr);
-	MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
-//	MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
-	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-	dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
+	MSG_WriteByte(&net_message, CPACCEPT);
+	MSG_WriteLong(&net_message, dfunc.GetSocketPort(&myip));
+	*((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+	dfunc.Write(net_message.data, net_message.cursize, &clientaddr);
 	SZ_Clear(&net_message);
 
 	return sock;
+done:
+	close(clientaddr.fd);
+	return nil;
 }
 
 qsocket_t *Datagram_CheckNewConnections (void)
@@ -1065,130 +588,17 @@
 	qsocket_t *ret = nil;
 
 	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-		if (net_landrivers[net_landriverlevel].initialized)
+		if (landrv[net_landriverlevel].initialized)
 			if ((ret = _Datagram_CheckNewConnections ()) != nil)
 				break;
 	return ret;
 }
 
-
-static void _Datagram_SearchForHosts (qboolean xmit)
-{
-	int		ret;
-	int		n;
-	int		i;
-	struct qsockaddr readaddr;
-	struct qsockaddr myaddr;
-	int		control;
-
-	dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
-	if (xmit)
-	{
-		SZ_Clear(&net_message);
-		// save space for the header, filled in later
-		MSG_WriteLong(&net_message, 0);
-		MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
-		MSG_WriteString(&net_message, "QUAKE");
-		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-		dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);
-		SZ_Clear(&net_message);
-	}
-
-	while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
-	{
-		if (ret < sizeof(int))
-			continue;
-		net_message.cursize = ret;
-
-		// don't answer our own query
-		if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0)
-			continue;
-
-		// is the cache full?
-		if (hostCacheCount == HOSTCACHESIZE)
-			continue;
-
-		MSG_BeginReading ();
-		control = BigLong(*((int *)net_message.data));
-		MSG_ReadLong();
-		if (control == -1)
-			continue;
-		if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
-			continue;
-		if ((control & NETFLAG_LENGTH_MASK) != ret)
-			continue;
-
-		if (MSG_ReadByte() != CCREP_SERVER_INFO)
-			continue;
-
-		dfunc.GetAddrFromName(MSG_ReadString(), &readaddr);
-		// search the cache for this server
-		for (n = 0; n < hostCacheCount; n++)
-			if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0)
-				break;
-
-		// is it already there?
-		if (n < hostCacheCount)
-			continue;
-
-		// add it
-		hostCacheCount++;
-		strcpy(hostcache[n].name, MSG_ReadString());
-		strcpy(hostcache[n].map, MSG_ReadString());
-		hostcache[n].users = MSG_ReadByte();
-		hostcache[n].maxusers = MSG_ReadByte();
-		if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
-		{
-			strcpy(hostcache[n].cname, hostcache[n].name);
-			hostcache[n].cname[14] = 0;
-			strcpy(hostcache[n].name, "*");
-			strcat(hostcache[n].name, hostcache[n].cname);
-		}
-		memcpy(&hostcache[n].addr, &readaddr, sizeof readaddr);
-		hostcache[n].driver = net_driverlevel;
-		hostcache[n].ldriver = net_landriverlevel;
-		strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr));
-
-		// check for a name conflict
-		for (i = 0; i < hostCacheCount; i++)
-		{
-			if (i == n)
-				continue;
-			if(cistrcmp(hostcache[n].name, hostcache[i].name) == 0)
-			{
-				i = strlen(hostcache[n].name);
-				if (i < 15 && hostcache[n].name[i-1] > '8')
-				{
-					hostcache[n].name[i] = '0';
-					hostcache[n].name[i+1] = 0;
-				}
-				else
-					hostcache[n].name[i-1]++;
-				i = -1;
-			}
-		}
-	}
-}
-
-void Datagram_SearchForHosts (qboolean xmit)
-{
-	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-	{
-		if (hostCacheCount == HOSTCACHESIZE)
-			break;
-		if (net_landrivers[net_landriverlevel].initialized)
-			_Datagram_SearchForHosts (xmit);
-	}
-}
-
-
 static qsocket_t *_Datagram_Connect (char *host)
 {
-	struct qsockaddr sendaddr;
-	struct qsockaddr readaddr;
+	Addr sendaddr;
+	Addr readaddr;
 	qsocket_t	*sock;
-	int			newsock;
 	int			ret = 0;
 	int			reps;
 	double		start_time;
@@ -1195,58 +605,47 @@
 	int			control;
 	char		*reason;
 
+	memset(&sendaddr, 0, sizeof sendaddr);
+	memset(&readaddr, 0, sizeof readaddr);
+
 	// see if we can resolve the host name
-	if (dfunc.GetAddrFromName(host, &sendaddr) == -1)
+	if (dfunc.getip(host, &sendaddr) == -1){
 		return nil;
+	}
 
-	newsock = dfunc.OpenSocket (0);
-	if (newsock == -1)
-		return nil;
-
 	sock = NET_NewQSocket ();
 	if (sock == nil)
 		goto ErrorReturn2;
-	sock->socket = newsock;
+	sock->socket = 1;
 	sock->landriver = net_landriverlevel;
 
 	// connect to the host
-	if (dfunc.Connect (newsock, &sendaddr) == -1)
+	if (dfunc.Connect(&sendaddr) == -1)
 		goto ErrorReturn;
+	memcpy(&readaddr, &sendaddr, sizeof readaddr);
 
 	// send the connection request
 	Con_Printf("trying...\n"); SCR_UpdateScreen ();
 	start_time = net_time;
 
+	UDP_Listen(1);
 	for (reps = 0; reps < 3; reps++)
 	{
 		SZ_Clear(&net_message);
 		// save space for the header, filled in later
 		MSG_WriteLong(&net_message, 0);
-		MSG_WriteByte(&net_message, CCREQ_CONNECT);
+		MSG_WriteByte(&net_message, CQCONNECT);
 		MSG_WriteString(&net_message, "QUAKE");
-		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
-		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-		dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr);
+		MSG_WriteByte(&net_message, NETVERSION);
+		*((int *)net_message.data) = BigLong(NFCTL | (net_message.cursize & NFMASK));
+		dfunc.Write(net_message.data, net_message.cursize, &sendaddr);
 		SZ_Clear(&net_message);
 		do
 		{
-			ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr);
+			ret = dfunc.Read(net_message.data, net_message.maxsize, &readaddr);
 			// if we got something, validate it
 			if (ret > 0)
 			{
-				// is it from the right place?
-				if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0)
-				{
-#ifdef DEBUG
-					Con_Printf("wrong reply address\n");
-					Con_Printf("Expected: %s\n", StrAddr (&sendaddr));
-					Con_Printf("Received: %s\n", StrAddr (&readaddr));
-					SCR_UpdateScreen ();
-#endif
-					ret = 0;
-					continue;
-				}
-
 				if (ret < sizeof(int))
 				{
 					ret = 0;
@@ -1263,12 +662,12 @@
 					ret = 0;
 					continue;
 				}
-				if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
+				if ((control & (~NFMASK)) !=  NFCTL)
 				{
 					ret = 0;
 					continue;
 				}
-				if ((control & NETFLAG_LENGTH_MASK) != ret)
+				if ((control & NFMASK) != ret)
 				{
 					ret = 0;
 					continue;
@@ -1281,6 +680,20 @@
 		Con_Printf("still trying...\n"); SCR_UpdateScreen ();
 		start_time = SetNetTime();
 	}
+	/* bullshit workaround for non-plan9 servers replying from different
+	 * ports.  because of this workaround, multiple instances on the same
+	 * host all require different ports prior to connection.  if someone
+	 * has a better solution, i'm all ears. */
+	start_time = SetNetTime();
+	do{
+		if(getnewcon(&sendaddr) > 0){
+			close(readaddr.fd);
+			memcpy(&readaddr, &sendaddr, sizeof readaddr);
+			break;
+		}
+		sleep(1);
+	}while(SetNetTime() - start_time < 2.5);
+	UDP_Listen(0);
 
 	if (ret == 0)
 	{
@@ -1299,7 +712,7 @@
 	}
 
 	ret = MSG_ReadByte();
-	if (ret == CCREP_REJECT)
+	if (ret == CPREJECT)
 	{
 		reason = MSG_ReadString();
 		Con_Printf(reason);
@@ -1307,9 +720,9 @@
 		goto ErrorReturn;
 	}
 
-	if (ret == CCREP_ACCEPT)
+	if (ret == CPACCEPT)
 	{
-		memcpy(&sock->addr, &sendaddr, sizeof sendaddr);
+		memcpy(&sock->addr, &readaddr, sizeof readaddr);
 		dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());
 	}
 	else
@@ -1320,27 +733,18 @@
 		goto ErrorReturn;
 	}
 
-	dfunc.GetNameFromAddr (&sendaddr, sock->address);
+	strcpy(sock->address, dfunc.AddrToString(&sendaddr));
 
 	Con_Printf ("Connection accepted\n");
 	sock->lastMessageTime = SetNetTime();
 
-	// switch the connection to the specified address
-	if (dfunc.Connect (newsock, &sock->addr) == -1)
-	{
-		reason = "Connect to Game failed";
-		Con_Printf("%s\n", reason);
-		strcpy(m_return_reason, reason);
-		goto ErrorReturn;
-	}
-
 	m_return_onerror = false;
 	return sock;
 
 ErrorReturn:
+	close(readaddr.fd);
 	NET_FreeQSocket(sock);
 ErrorReturn2:
-	dfunc.CloseSocket(newsock);
 	if (m_return_onerror)
 	{
 		key_dest = key_menu;
@@ -1355,8 +759,14 @@
 	qsocket_t *ret = nil;
 
 	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
-		if (net_landrivers[net_landriverlevel].initialized)
+		if (landrv[net_landriverlevel].initialized)
 			if ((ret = _Datagram_Connect (host)) != nil)
 				break;
 	return ret;
+}
+
+void
+Datagram_Close(qsocket_t *s)
+{
+	close(s->addr.fd);
 }
--- a/net_loop.c
+++ b/net_loop.c
@@ -25,25 +25,6 @@
 {
 }
 
-
-void Loop_SearchForHosts (qboolean) /*xmit*/
-{
-	if (!sv.active)
-		return;
-
-	hostCacheCount = 1;
-	if(strcmp(hostname.string, "UNNAMED") == 0)
-		strcpy(hostcache[0].name, "local");
-	else
-		strcpy(hostcache[0].name, hostname.string);
-	strcpy(hostcache[0].map, sv.name);
-	hostcache[0].users = net_activeconnections;
-	hostcache[0].maxusers = svs.maxclients;
-	hostcache[0].driver = net_driverlevel;
-	strcpy(hostcache[0].cname, "local");
-}
-
-
 qsocket_t *Loop_Connect (char *host)
 {
 	if(strcmp(host, "local") != 0)
--- a/net_main.c
+++ b/net_main.c
@@ -8,35 +8,6 @@
 qsocket_t	*net_freeSockets = nil;
 int			net_numsockets = 0;
 
-qboolean	serialAvailable = false;
-qboolean	ipxAvailable = false;
-qboolean	tcpipAvailable = false;
-
-int			net_hostport;
-int			DEFAULTnet_hostport = 26000;
-
-char		my_ipx_address[NET_NAMELEN];
-char		my_tcpip_address[NET_NAMELEN];
-
-void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
-void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
-void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
-void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
-
-int listener;
-
-qboolean	slistInProgress = false;
-qboolean	slistSilent = false;
-qboolean	slistLocal = true;
-static double	slistStartTime;
-static int		slistLastShown;
-
-static void Slist_Send(void *);
-static void Slist_Poll(void *);
-PollProcedure	slistSendProcedure = {nil, 0.0, Slist_Send};
-PollProcedure	slistPollProcedure = {nil, 0.0, Slist_Poll};
-
-
 sizebuf_t		net_message;
 int				net_activeconnections = 0;
 
@@ -48,23 +19,60 @@
 cvar_t	net_messagetimeout = {"net_messagetimeout","300"};
 cvar_t	hostname = {"hostname", "UNNAMED"};
 
-qboolean	configRestored = false;
-cvar_t	config_com_port = {"_config_com_port", "0x3f8", true};
-cvar_t	config_com_irq = {"_config_com_irq", "4", true};
-cvar_t	config_com_baud = {"_config_com_baud", "57600", true};
-cvar_t	config_com_modem = {"_config_com_modem", "1", true};
-cvar_t	config_modem_dialtype = {"_config_modem_dialtype", "T", true};
-cvar_t	config_modem_clear = {"_config_modem_clear", "ATZ", true};
-cvar_t	config_modem_init = {"_config_modem_init", "", true};
-cvar_t	config_modem_hangup = {"_config_modem_hangup", "AT H", true};
+Netdrv netdrv[MAX_NET_DRIVERS] = {
+	{
+	"Loopback",
+	false,
+	Loop_Init,
+	Loop_Connect,
+	Loop_CheckNewConnections,
+	Loop_GetMessage,
+	Loop_SendMessage,
+	Loop_SendUnreliableMessage,
+	Loop_CanSendMessage,
+	Loop_CanSendUnreliableMessage,
+	Loop_Close,
+	Loop_Shutdown
+	}
+	,
+	{
+	"Datagram",
+	false,
+	Datagram_Init,
+	Datagram_Connect,
+	Datagram_CheckNewConnections,
+	Datagram_GetMessage,
+	Datagram_SendMessage,
+	Datagram_SendUnreliableMessage,
+	Datagram_CanSendMessage,
+	Datagram_CanSendUnreliableMessage,
+	Datagram_Close,
+	Datagram_Shutdown
+	}
+};
+int net_numdrivers = 2;
 
-#ifdef IDGODS
-cvar_t	idgods = {"idgods", "0"};
-#endif
+Landrv landrv[MAX_NET_DRIVERS] = {
+	{
+	"UDP",
+	false,
+	UDP_Init,
+	UDP_Shutdown,
+	UDP_Connect,
+	udpread,
+	udpwrite,
+	UDP_AddrToString,
+	getip,
+	UDP_AddrCompare,
+	UDP_GetSocketPort,
+	UDP_SetSocketPort
+	}
+};
+int net_numlandrivers = 1;
 
 // these two macros are to make the code more readable
-#define sfunc	net_drivers[sock->driver]
-#define dfunc	net_drivers[net_driverlevel]
+#define sfunc	netdrv[sock->driver]
+#define dfunc	netdrv[net_driverlevel]
 
 int	net_driverlevel;
 
@@ -120,6 +128,7 @@
 	sock->receiveSequence = 0;
 	sock->unreliableReceiveSequence = 0;
 	sock->receiveMessageLength = 0;
+	sock->addr.fd = -1;
 
 	return sock;
 }
@@ -143,6 +152,8 @@
 		if (!s)
 			fatal ("NET_FreeQSocket: not active\n");
 	}
+	if(sock->addr.fd >= 0)
+		close(sock->addr.fd);
 
 	// add it to free list
 	sock->next = net_freeSockets;
@@ -150,26 +161,6 @@
 	sock->disconnected = true;
 }
 
-
-static void NET_Listen_f (void)
-{
-	if (Cmd_Argc () != 2)
-	{
-		Con_Printf ("\"listen\" is \"%ud\"\n", listener ? 1 : 0);
-		return;
-	}
-
-	listener = atoi(Cmd_Argv(1)) ? true : false;
-
-	for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
-	{
-		if (net_drivers[net_driverlevel].initialized == false)
-			continue;
-		dfunc.Listen (listener);
-	}
-}
-
-
 static void MaxPlayers_f (void)
 {
 	int 	n;
@@ -195,12 +186,6 @@
 		Con_Printf ("\"maxplayers\" set to \"%ud\"\n", n);
 	}
 
-	if ((n == 1) && listener)
-		Cbuf_AddText ("listen 0\n");
-
-	if ((n > 1) && (!listener))
-		Cbuf_AddText ("listen 1\n");
-
 	svs.maxclients = n;
 	if (n == 1)
 		setcvar ("deathmatch", "0");
@@ -215,9 +200,13 @@
 
 	if (Cmd_Argc () != 2)
 	{
-		Con_Printf ("\"port\" is \"%ud\"\n", net_hostport);
+		Con_Printf ("\"port\" is \"%s\"\n", myip.srv);
 		return;
 	}
+	if(sv.active){
+		Con_Printf("port cannot be changed while a server is running.\n");
+		return;
+	}
 
 	n = atoi(Cmd_Argv(1));
 	if (n < 1 || n > 65534)
@@ -225,116 +214,9 @@
 		Con_Printf ("Bad value, must be between 1 and 65534\n");
 		return;
 	}
-
-	DEFAULTnet_hostport = n;
-	net_hostport = n;
-
-	if (listener)
-	{
-		// force a change to the new port
-		Cbuf_AddText ("listen 0\n");
-		Cbuf_AddText ("listen 1\n");
-	}
+	snprint(myip.srv, sizeof myip.srv, "%hud", n);
 }
 
-
-static void PrintSlistHeader(void)
-{
-	Con_Printf("Server          Map             Users\n");
-	Con_Printf("--------------- --------------- -----\n");
-	slistLastShown = 0;
-}
-
-
-static void PrintSlist(void)
-{
-	int n;
-
-	for (n = slistLastShown; n < hostCacheCount; n++)
-	{
-		if (hostcache[n].maxusers)
-			Con_Printf("%-15.15s %-15.15s %2ud/%2ud\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
-		else
-			Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
-	}
-	slistLastShown = n;
-}
-
-
-static void PrintSlistTrailer(void)
-{
-	if (hostCacheCount)
-		Con_Printf("== end list ==\n\n");
-	else
-		Con_Printf("No Quake servers found.\n\n");
-}
-
-
-void NET_Slist_f (void)
-{
-	if (slistInProgress)
-		return;
-
-	if (! slistSilent)
-	{
-		Con_Printf("Looking for Quake servers...\n");
-		PrintSlistHeader();
-	}
-
-	slistInProgress = true;
-	slistStartTime = dtime();
-
-	SchedulePollProcedure(&slistSendProcedure, 0.0);
-	SchedulePollProcedure(&slistPollProcedure, 0.1);
-
-	hostCacheCount = 0;
-}
-
-
-static void Slist_Send(void *)
-{
-	for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
-	{
-		if (!slistLocal && net_driverlevel == 0)
-			continue;
-		if (net_drivers[net_driverlevel].initialized == false)
-			continue;
-		dfunc.SearchForHosts (true);
-	}
-
-	if ((dtime() - slistStartTime) < 0.5)
-		SchedulePollProcedure(&slistSendProcedure, 0.75);
-}
-
-
-static void Slist_Poll(void *)
-{
-	for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
-	{
-		if (!slistLocal && net_driverlevel == 0)
-			continue;
-		if (net_drivers[net_driverlevel].initialized == false)
-			continue;
-		dfunc.SearchForHosts (false);
-	}
-
-	if (! slistSilent)
-		PrintSlist();
-
-	if ((dtime() - slistStartTime) < 1.5)
-	{
-		SchedulePollProcedure(&slistPollProcedure, 0.1);
-		return;
-	}
-
-	if (! slistSilent)
-		PrintSlistTrailer();
-	slistInProgress = false;
-	slistSilent = false;
-	slistLocal = true;
-}
-
-
 /*
 ===================
 NET_Connect
@@ -341,80 +223,26 @@
 ===================
 */
 
-int hostCacheCount = 0;
-hostcache_t hostcache[HOSTCACHESIZE];
-
 qsocket_t *NET_Connect (char *host)
 {
 	qsocket_t		*ret;
-	int				n;
 	int				numdrivers = net_numdrivers;
 
 	SetNetTime();
 
-	if (host && *host == 0)
-		host = nil;
+	if (host == nil || *host == 0)
+		return nil;
+	if(cistrcmp(host, "local") == 0)
+		numdrivers = 1;
 
-	if (host)
-	{
-		if(cistrcmp(host, "local") == 0)
-		{
-			numdrivers = 1;
-			goto JustDoIt;
-		}
-
-		if (hostCacheCount)
-		{
-			for (n = 0; n < hostCacheCount; n++)
-				if(cistrcmp(host, hostcache[n].name) == 0)
-				{
-					host = hostcache[n].cname;
-					break;
-				}
-			if (n < hostCacheCount)
-				goto JustDoIt;
-		}
-	}
-
-	slistSilent = host ? true : false;
-	NET_Slist_f ();
-
-	while(slistInProgress)
-		NET_Poll();
-
-	if (host == nil)
-	{
-		if (hostCacheCount != 1)
-			return nil;
-		host = hostcache[0].cname;
-		Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
-	}
-
-	if (hostCacheCount)
-		for (n = 0; n < hostCacheCount; n++)
-			if(cistrcmp(host, hostcache[n].name) == 0)
-			{
-				host = hostcache[n].cname;
-				break;
-			}
-
-JustDoIt:
 	for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
 	{
-		if (net_drivers[net_driverlevel].initialized == false)
+		if (netdrv[net_driverlevel].initialized == false)
 			continue;
 		ret = dfunc.Connect (host);
 		if (ret)
 			return ret;
 	}
-
-	if (host)
-	{
-		Con_Printf("\n");
-		PrintSlistHeader();
-		PrintSlist();
-		PrintSlistTrailer();
-	}
 	
 	return nil;
 }
@@ -427,9 +255,9 @@
 
 	for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
 	{
-		if (net_drivers[net_driverlevel].initialized == false)
+		if (netdrv[net_driverlevel].initialized == false)
 			continue;
-		if (net_driverlevel && listener == false)
+		if (net_driverlevel && !sv.active)
 			continue;
 		ret = dfunc.CheckNewConnections ();
 		if(ret)
@@ -446,10 +274,9 @@
 */
 void NET_Close (qsocket_t *sock)
 {
-	if (!sock)
+	if(sock == nil)
 		return;
-
-	if (sock->disconnected)
+	if(sock->disconnected)
 		return;
 
 	SetNetTime();
@@ -497,6 +324,7 @@
 	{
 		if (net_time - sock->lastMessageTime > net_messagetimeout.value)
 		{
+			fprint(2, "NET_GetMessage: sock %#p timed out\n", sock);
 			NET_Close(sock);
 			return -1;
 		}
@@ -686,10 +514,8 @@
 void NET_Init (void)
 {
 	int			i;
-	int			controlSocket;
 	qsocket_t	*s;
 
-	net_hostport = DEFAULTnet_hostport;
 	net_numsockets = svs.maxclientslimit;
 	if (cls.state != ca_dedicated)
 		net_numsockets++;
@@ -709,39 +535,16 @@
 
 	Cvar_RegisterVariable (&net_messagetimeout);
 	Cvar_RegisterVariable (&hostname);
-	Cvar_RegisterVariable (&config_com_port);
-	Cvar_RegisterVariable (&config_com_irq);
-	Cvar_RegisterVariable (&config_com_baud);
-	Cvar_RegisterVariable (&config_com_modem);
-	Cvar_RegisterVariable (&config_modem_dialtype);
-	Cvar_RegisterVariable (&config_modem_clear);
-	Cvar_RegisterVariable (&config_modem_init);
-	Cvar_RegisterVariable (&config_modem_hangup);
-#ifdef IDGODS
-	Cvar_RegisterVariable (&idgods);
-#endif
 
-	Cmd_AddCommand ("slist", NET_Slist_f);
-	Cmd_AddCommand ("listen", NET_Listen_f);
 	Cmd_AddCommand ("maxplayers", MaxPlayers_f);
 	Cmd_AddCommand ("port", NET_Port_f);
 
 	// initialize all the drivers
-	for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
-		{
-		controlSocket = net_drivers[net_driverlevel].Init();
-		if (controlSocket == -1)
+	for(net_driverlevel=0; net_driverlevel<net_numdrivers; net_driverlevel++){
+		if(netdrv[net_driverlevel].Init() < 0)
 			continue;
-		net_drivers[net_driverlevel].initialized = true;
-		net_drivers[net_driverlevel].controlSock = controlSocket;
-		if (listener)
-			net_drivers[net_driverlevel].Listen (true);
-		}
-
-	if (*my_ipx_address)
-		print("IPX address %s\n", my_ipx_address);
-	if (*my_tcpip_address)
-		print("TCP/IP address %s\n", my_tcpip_address);
+		netdrv[net_driverlevel].initialized = true;
+	}
 }
 
 /*
@@ -764,85 +567,10 @@
 //
 	for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
 	{
-		if (net_drivers[net_driverlevel].initialized == true)
+		if (netdrv[net_driverlevel].initialized == true)
 		{
-			net_drivers[net_driverlevel].Shutdown ();
-			net_drivers[net_driverlevel].initialized = false;
+			netdrv[net_driverlevel].Shutdown ();
+			netdrv[net_driverlevel].initialized = false;
 		}
 	}
 }
-
-
-static PollProcedure *pollProcedureList = nil;
-
-void NET_Poll(void)
-{
-	PollProcedure *pp;
-	qboolean	useModem;
-
-	if (!configRestored)
-	{
-		if (serialAvailable)
-		{
-			if (config_com_modem.value == 1.0)
-				useModem = true;
-			else
-				useModem = false;
-			SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
-			SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
-		}
-		configRestored = true;
-	}
-
-	SetNetTime();
-
-	for (pp = pollProcedureList; pp; pp = pp->next)
-	{
-		if (pp->nextTime > net_time)
-			break;
-		pollProcedureList = pp->next;
-		pp->procedure(pp->arg);
-	}
-}
-
-
-void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
-{
-	PollProcedure *pp, *prev;
-
-	proc->nextTime = dtime() + timeOffset;
-	for (pp = pollProcedureList, prev = nil; pp; pp = pp->next)
-	{
-		if (pp->nextTime >= proc->nextTime)
-			break;
-		prev = pp;
-	}
-
-	if (prev == nil)
-	{
-		proc->next = pollProcedureList;
-		pollProcedureList = proc;
-		return;
-	}
-
-	proc->next = pp;
-	prev->next = proc;
-}
-
-
-#ifdef IDGODS
-#define IDNET	0xc0f62800
-
-qboolean IsID(struct qsockaddr *addr)
-{
-	if (idgods.value == 0.0)
-		return false;
-
-	if (addr->sa_family != 2)
-		return false;
-
-	if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)
-		return true;
-	return false;
-}
-#endif
--- a/net_udp.c
+++ b/net_udp.c
@@ -1,396 +1,234 @@
 #include <u.h>
 #include <libc.h>
+#include <ip.h>
+#include <thread.h>
 #include "dat.h"
 #include "quakedef.h"
 #include "fns.h"
 
-/* TODO */
+Addr myip;
 
-/*
-extern int gethostname (char *, int);
-extern int close (int);
+static int lpid = -1, afd;
+static Channel *lchan;
 
-extern cvar_t hostname;
-
-static int net_acceptsocket = -1;		// socket for fielding new connections
-static int net_controlsocket;
-static int net_broadcastsocket = 0;
-static struct qsockaddr broadcastaddr;
-
-static u32int myAddr;
-*/
-
-int net_controlsocket;
-
-
-int UDP_Init (void)
+int
+UDP_Init(void)
 {
-	/*
-	struct hostent *local;
-	char	buff[MAXHOSTNAMELEN];
-	struct qsockaddr addr;
-	char *colon;
-	
-	if (COM_CheckParm ("-noudp"))
-		return -1;
-	// determine my name & address
-	gethostname(buff, MAXHOSTNAMELEN);
-	local = gethostbyname(buff);
-	myAddr = *(int *)local->h_addr_list[0];
+	char *s;
+	uchar ip[IPaddrlen];
 
-	// if the quake hostname isn't set, set it to the machine name
+	fmtinstall('I', eipfmt);
 	if(strcmp(hostname.string, "UNNAMED") == 0)
-	{
-		buff[15] = 0;
-		setcvar ("hostname", buff);
-	}
-
-	if ((net_controlsocket = UDP_OpenSocket (0)) == -1)
-		fatal("UDP_Init: Unable to open control socket\n");
-
-	((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
-	((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
-	((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(net_hostport);
-
-	UDP_GetSocketAddr (net_controlsocket, &addr);
-	strcpy(my_tcpip_address, UDP_AddrToString(&addr));
-	colon = strrchr(my_tcpip_address, ':');
-	if (colon)
-		*colon = 0;
-
-	Con_Printf("UDP Initialized\n");
-	tcpipAvailable = true;
-
-	return net_controlsocket;
-	*/
-	return -1;
+		if((s = getenv("sysname")) != nil){
+			setcvar("hostname", s);
+			free(s);
+		}
+	myipaddr(ip, nil);
+	snprint(myip.ip, sizeof myip.ip, "%I", ip);
+	snprint(myip.srv, sizeof myip.srv, "%hud", Udpport);
+	return 0;
 }
 
-void UDP_Shutdown (void)
+void
+UDP_Shutdown(void)
 {
 	UDP_Listen(false);
-	UDP_CloseSocket(net_controlsocket);
 }
 
-void UDP_Listen (qboolean /*state*/)
+static void
+lproc(void *)
 {
-	/*
-	// enable listening
-	if (state)
-	{
-		if (net_acceptsocket != -1)
-			return;
-		if ((net_acceptsocket = UDP_OpenSocket (net_hostport)) == -1)
-			fatal ("UDP_Listen: Unable to open accept socket\n");
-		return;
-	}
+	int fd, lfd;
+	char adir[40], ldir[40], data[100];
 
-	// disable listening
-	if (net_acceptsocket == -1)
-		return;
-	UDP_CloseSocket (net_acceptsocket);
-	net_acceptsocket = -1;
-	*/
+	snprint(data, sizeof data, "%s/udp!*!%s", netmtpt, myip.srv);
+	if((afd = announce(data, adir)) < 0)
+		sysfatal("announce: %r");
+	for(;;){
+		if((lfd = listen(adir, ldir)) < 0
+			|| (fd = accept(lfd, ldir)) < 0
+			|| close(lfd) < 0
+			|| send(lchan, &fd) < 0)
+			break;
+	}
 }
 
-int UDP_OpenSocket (int /*port*/)
+static void
+udpname(void)
 {
-	/*
-	int newsocket;
-	struct sockaddr_in address;
-	qboolean _true = true;
-
-	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
-		return -1;
-
-	if (ioctl (newsocket, FIONBIO, (char *)&_true) == -1)
-		goto ErrorReturn;
-
-	address.sin_family = AF_INET;
-	address.sin_addr.s_addr = INADDR_ANY;
-	address.sin_port = htons(port);
-	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
-		goto ErrorReturn;
-
-	return newsocket;
-
-ErrorReturn:
-	close (newsocket);
-	return -1;
-	*/
-	return -1;
+	if((lchan = chancreate(sizeof(int), 0)) == nil)
+		sysfatal("chancreate: %r");
+	if((lpid = proccreate(lproc, nil, 8192)) < 0)
+		sysfatal("proccreate lproc: %r");
 }
 
-int UDP_CloseSocket (int /*socket*/)
+void
+UDP_Listen(qboolean on)
 {
-	/*
-	if (socket == net_broadcastsocket)
-		net_broadcastsocket = 0;
-	return close (socket);
-	*/
-	return -1;
+	if(lpid < 0){
+		if(on)
+			udpname();
+		return;
+	}
+	if(on)
+		return;
+	close(afd);
+	chanclose(lchan);
+	threadint(lpid);
+	chanfree(lchan);
+	lpid = -1;
 }
 
-/*
-============
-PartialIPAddress
-
-this lets you type only as much of the net address as required, using
-the local network components to fill in the rest
-============
-*/
-static int PartialIPAddress (char */*in*/, struct qsockaddr */*hostaddr*/)
+void
+udpinfo(Addr *a)
 {
-	/*
-	char buff[256];
-	char *b;
-	int addr;
-	int num;
-	int mask;
-	int run;
-	int port;
-	
-	buff[0] = '.';
-	b = buff;
-	strcpy(buff+1, in);
-	if (buff[1] == '.')
-		b++;
+	NetConnInfo *nc;
 
-	addr = 0;
-	mask=-1;
-	while (*b == '.')
-	{
-		b++;
-		num = 0;
-		run = 0;
-		while (!( *b < '0' || *b > '9'))
-		{
-		  num = num*10 + *b++ - '0';
-		  if (++run > 3)
-		  	return -1;
-		}
-		if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
-			return -1;
-		if (num < 0 || num > 255)
-			return -1;
-		mask<<=8;
-		addr = (addr<<8) + num;
+	if((nc = getnetconninfo(nil, a->fd)) == nil){
+		fprint(2, "getnetconninfo: %r\n");
+		return;
 	}
-	
-	if (*b++ == ':')
-		port = atoi(b);
-	else
-		port = net_hostport;
-
-	hostaddr->sa_family = AF_INET;
-	((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);	
-	((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
-	
-	return 0;
-	*/
-	return -1;
+	strncpy(a->ip, nc->raddr, sizeof(a->ip)-1);
+	strncpy(a->srv, nc->rserv, sizeof(a->srv)-1);
+	strncpy(a->sys, nc->rsys, sizeof(a->sys)-1);
+	free(nc);
 }
 
-int UDP_Connect (int /*socket*/, struct qsockaddr */*addr*/)
+int
+UDP_Connect(Addr *a)
 {
+	if((a->fd = dial(netmkaddr(a->ip, "udp", a->srv), myip.srv, nil, nil)) < 0){
+		fprint(2, "dial: %r\n");
+		return -1;
+	}
 	return 0;
 }
 
-int UDP_CheckNewConnections (void)
+int
+getnewcon(Addr *a)
 {
-	/*
-	u32int	available;
-
-	if (net_acceptsocket == -1)
-		return -1;
-
-	if (ioctl (net_acceptsocket, FIONREAD, &available) == -1)
-		fatal ("UDP: ioctlsocket (FIONREAD) failed\n");
-	if (available)
-		return net_acceptsocket;
-	return -1;
-	*/
-	return -1;
-}
-
-int UDP_Read (int /*socket*/, byte */*buf*/, int /*len*/, struct qsockaddr */*addr*/)
-{
-	/*
-	int addrlen = sizeof (struct qsockaddr);
-	int ret;
-
-	ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
-	if (ret == -1 && (errno == EWOULDBLOCK || errno == ECONNREFUSED))
+	if(lpid < 0)
 		return 0;
-	return ret;
-	*/
-	return -1;
+	if(nbrecv(lchan, &a->fd) == 0)
+		return 0;
+	udpinfo(a);
+	return 1;
 }
 
-int UDP_MakeSocketBroadcastCapable (int /*socket*/)
+int
+udpread(byte *buf, int len, Addr *a)
 {
-	/*
-	int				i = 1;
+	int n;
 
-	// make this socket broadcast capable
-	if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
+	if(flen(a->fd) < 1)
+		return 0;
+	if((n = read(a->fd, buf, len)) <= 0){
+		fprint(2, "udpread: %r\n");
 		return -1;
-	net_broadcastsocket = socket;
-
-	return 0;
-	*/
-	return -1;
+	}
+	return n;
 }
 
-int UDP_Broadcast (int /*socket*/, byte */*buf*/, int /*len*/)
+int
+udpwrite(uchar *buf, int len, Addr *a)
 {
-	/*
-	int ret;
-
-	if (socket != net_broadcastsocket)
-	{
-		if (net_broadcastsocket != 0)
-			fatal("Attempted to use multiple broadcasts sockets\n");
-		ret = UDP_MakeSocketBroadcastCapable (socket);
-		if (ret == -1)
-		{
-			Con_Printf("Unable to make socket broadcast capable\n");
-			return ret;
-		}
+	if(write(a->fd, buf, len) != len){
+		fprint(2, "udpwrite: %r\n");
+		return -1;
 	}
-
-	return UDP_Write (socket, buf, len, &broadcastaddr);
-	*/
-	return -1;
+	return len;
 }
 
-int UDP_Write (int /*socket*/, byte */*buf*/, int /*len*/, struct qsockaddr */*addr*/)
+char *
+UDP_AddrToString(Addr *a)
 {
-	/*
-	int ret;
+	char *p;
+	static char buf[52];
 
-	ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
-	if (ret == -1 && errno == EWOULDBLOCK)
-		return 0;
-	return ret;
-	*/
-	return -1;
+	strncpy(buf, a->sys, sizeof(buf)-1);
+	if((p = strrchr(buf, '!')) != nil)
+		*p = ':';
+	return buf;
 }
 
-char *UDP_AddrToString (struct qsockaddr */*addr*/)
+int
+UDP_Broadcast(uchar *buf, int len)
 {
-	/*
-	static char buffer[22];
-	int haddr;
+	int fd;
+	char ip[46];
 
-	haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
-	sprint(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port));
-	return buffer;
-	*/
-	return nil;
-}
-
-int UDP_StringToAddr (char */*string*/, struct qsockaddr */*addr*/)
-{
-	/*
-	int ha1, ha2, ha3, ha4, hp;
-	int ipaddr;
-
-	sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
-	ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
-
-	addr->sa_family = AF_INET;
-	((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
-	((struct sockaddr_in *)addr)->sin_port = htons(hp);
+	snprint(ip, sizeof ip, "%I", IPv4bcast);
+	if((fd = dial(netmkaddr(ip, "udp", myip.srv), myip.srv, nil, nil)) < 0){
+		fprint(2, "UDP_Broadcast: %r\n");
+		return -1;
+	}
+	if(write(fd, buf, len) != len)
+		fprint(2, "write: %r\n");
+	close(fd);
 	return 0;
-	*/
-	return -1;
 }
 
-int UDP_GetSocketAddr (int /*socket*/, struct qsockaddr */*addr*/)
+int
+getip(char *s, Addr *a)
 {
-	/*
-	int addrlen = sizeof(struct qsockaddr);
-	unsigned int a;
+	int fd, n;
+	char buf[128], *f[4], *p;
 
-	memset(addr, 0, sizeof(struct qsockaddr));
-	getsockname(socket, (struct sockaddr *)addr, &addrlen);
-	a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
-	if (a == 0 || a == inet_addr("127.0.0.1"))
-		((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
+	snprint(buf, sizeof buf, "%s/cs", netmtpt);
+	if((fd = open(buf, ORDWR)) < 0)
+		sysfatal("open: %r");
 
-	return 0;
-	*/
-	return -1;
-}
-
-int UDP_GetNameFromAddr (struct qsockaddr */*addr*/, char */*name*/)
-{
-	/*
-	struct hostent *hostentry;
-
-	hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
-	if (hostentry)
-	{
-		strncpy(name, (char *)hostentry->h_name, NET_NAMELEN - 1);
-		return 0;
+	if((p = strrchr(s, '!')) == nil)
+		p = myip.srv;
+	else
+		p++;
+	snprint(buf, sizeof buf, "udp!%s!%s", s, p);
+	n = strlen(buf);
+	if(write(fd, buf, n) != n){
+		fprint(2, "translating %s: %r\n", s);
+		return -1;
 	}
-
-	strcpy(name, UDP_AddrToString (addr));
-	return 0;
-	*/
-	return -1;
-}
-
-int UDP_GetAddrFromName(char */*name*/, struct qsockaddr */*addr*/)
-{
-	/*
-	struct hostent *hostentry;
-
-	if (name[0] >= '0' && name[0] <= '9')
-		return PartialIPAddress (name, addr);
-	
-	hostentry = gethostbyname (name);
-	if (!hostentry)
+	seek(fd, 0, 0);
+	if((n = read(fd, buf, sizeof(buf)-1)) <= 0){
+		fprint(2, "reading cs tables: %r");
 		return -1;
-
-	addr->sa_family = AF_INET;
-	((struct sockaddr_in *)addr)->sin_port = htons(net_hostport);	
-	((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
-
+	}
+	buf[n] = 0;
+	close(fd);
+	if(getfields(buf, f, 4, 0, " !") < 2)
+		goto err;
+	strncpy(a->ip, f[1], sizeof(a->ip)-1);
+	a->ip[sizeof(a->ip)-1] = 0;
+	strncpy(a->srv, f[2], sizeof(a->srv)-1);
+	a->srv[sizeof(a->srv)-1] = 0;
+	snprint(a->sys, sizeof a->sys, "%s!%s", a->ip, a->srv);
 	return 0;
-	*/
+err:
+	fprint(2, "bad cs entry %s", buf);
 	return -1;
 }
 
-int UDP_AddrCompare (struct qsockaddr */*addr1*/, struct qsockaddr */*addr2*/)
+int
+UDP_AddrCompare(Addr *a1, Addr *a2)
 {
-	/*
-	if (addr1->sa_family != addr2->sa_family)
+	if(strcmp(a1->ip, a2->ip) != 0)
 		return -1;
-
-	if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
-		return -1;
-
-	if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
+	if(strcmp(a1->srv, a2->srv) != 0)
 		return 1;
-
 	return 0;
-	*/
-	return -1;
 }
 
-int UDP_GetSocketPort (struct qsockaddr */*addr*/)
+ushort
+UDP_GetSocketPort(Addr *a)
 {
-	//return ntohs(((struct sockaddr_in *)addr)->sin_port);
-	return -1;
+	ushort p;
+
+	p = atoi(a->srv);
+	return p;
 }
 
-int UDP_SetSocketPort (struct qsockaddr */*addr*/, int /*port*/)
+void
+UDP_SetSocketPort(Addr *a, ushort port)
 {
-	/*
-	((struct sockaddr_in *)addr)->sin_port = htons(port);
-	return 0;
-	*/
-	return -1;
+	snprint(a->srv, sizeof a->srv, "%hud", port);	/* was htons'ed */
 }
--- a/qk1.c
+++ b/qk1.c
@@ -6,6 +6,7 @@
 #include "fns.h"
 
 mainstacksize = 512*1024;
+char *netmtpt = "/net";
 uchar *membase;
 int memsize;
 char *game;
@@ -108,7 +109,7 @@
 static void
 usage(void)
 {
-	fprint(2, "usage: %s [-dl] [-g game] [-m kB] [-s width height]\n", argv0);
+	fprint(2, "usage: %s [-d] [-g game] [-m kB] [-s width height] [-x netmtpt]\n", argv0);
 	exits("usage");
 }
 
@@ -121,8 +122,6 @@
 	ARGBEGIN{
 	case 'd':
 		dedicated = 1;
-	case 'l':
-		listener = 1;
 		break;
 	case 'g':
 		game = EARGF(usage());
@@ -138,6 +137,9 @@
 		vid.height = strtol(EARGF(usage()), nil, 0);
 		if(vid.width < 320 || vid.height < 200)
 			sysfatal("invalid scale resolution");
+		break;
+	case 'x':
+		netmtpt = EARGF(usage());
 		break;
 	default: usage();
 	}ARGEND
--- a/quakedef.h
+++ b/quakedef.h
@@ -130,10 +130,6 @@
 
 #define	SOUND_CHANNELS		8
 
-// This makes anyone on id's net privileged
-// Use for multiplayer testing only - VERY dangerous!!!
-// #define IDGODS
-
 typedef unsigned char 		byte;
 typedef enum {false, true}	qboolean;
 
--- a/server.h
+++ b/server.h
@@ -55,7 +55,6 @@
 	qboolean		active;				// false = client is free
 	qboolean		spawned;			// false = don't send datagrams
 	qboolean		dropasap;			// has been told to go to another level
-	qboolean		privileged;			// can execute any host command
 	qboolean		sendsignon;			// only valid before spawned
 
 	double			last_message;		// reliable messages must be sent
--- a/sv_main.c
+++ b/sv_main.c
@@ -255,13 +255,6 @@
 	client->message.maxsize = sizeof client->msgbuf;
 	client->message.allowoverflow = true;		// we can catch it
 
-#ifdef IDGODS
-	client->privileged = IsID(&client->netconnection->addr);
-#endif
-#ifndef IDGODS
-	client->privileged = false;				
-#endif
-
 	if(sv.loadgame)
 		memcpy(client->spawn_parms, spawn_parms, sizeof spawn_parms);
 	else{
@@ -1144,6 +1137,8 @@
 
 // create a baseline for more efficient communications
 	SV_CreateBaseline ();
+
+	UDP_Listen(svs.maxclients > 1);
 
 // send serverinfo to all connected clients
 	for (i=0,host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
--- a/sv_user.c
+++ b/sv_user.c
@@ -504,10 +504,7 @@
 				
 			case clc_stringcmd:	
 				s = MSG_ReadString ();
-				if (host_client->privileged)
-					ret = 2;
-				else
-					ret = 0;
+				ret = 0;
 				if (cistrncmp(s, "status", 6) == 0)
 					ret = 1;
 				else if (cistrncmp(s, "god", 3) == 0)