From a8f828a066773a59fdf646299359d35ae0e845af Mon Sep 17 00:00:00 2001 From: wyatt8740 Date: Mon, 6 Jan 2014 12:02:16 -0500 Subject: Removed accidental upload of copyrighted map files --- WinQuake/net_ipx.c | 1412 ++++++++++++++++++++++++++-------------------------- 1 file changed, 706 insertions(+), 706 deletions(-) (limited to 'WinQuake/net_ipx.c') diff --git a/WinQuake/net_ipx.c b/WinQuake/net_ipx.c index f0ab72e..75ae6fd 100644 --- a/WinQuake/net_ipx.c +++ b/WinQuake/net_ipx.c @@ -1,706 +1,706 @@ -/* -Copyright (C) 1996-1997 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ -// net_ipx.c - -#include -#include -#include - -#include "quakedef.h" -#include "dosisms.h" -#include "net_ipx.h" - -#define EIO 5 /* I/O error */ - -#define AF_NETWARE 64 - -#define IPX_OPEN 0 -#define IPX_CLOSE 1 -#define IPX_GETROUTE 2 -#define IPX_SEND 3 -#define IPX_LISTEN 4 -#define IPX_SCHEDULEEVENT 5 -#define IPX_CANCEL 6 -#define IPX_SCHEDULESPECIALEVENT 7 -#define IPX_GETINTERVALMARKER 8 -#define IPX_GETADDRESS 9 -#define IPX_RELINQUISH 10 - -#define PTYPE_UNKNOWN 0 -#define PTYPE_RIP 1 -#define PTYPE_ECHO 2 -#define PTYPE_ERROR 3 -#define PTYPE_IPX 4 -#define PTYPE_SPX 5 - -#pragma pack(1) - -typedef struct -{ - byte network[4]; - byte node[6]; - short socket; -} IPXaddr; - -struct sockaddr_ipx -{ - short sipx_family; - IPXaddr sipx_addr; - char sipx_zero[2]; -}; -#define sipx_port sipx_addr.socket - -typedef struct -{ - short checkSum; - short length; - byte transportControl; - byte type; - IPXaddr destination; - IPXaddr source; -} IPXheader; - -typedef struct ECBStructure -{ - struct ECBStructure *link; - unsigned short ESR_off; - unsigned short ESR_seg; - byte inUse; - byte completionCode; - short socket; - byte IPXWorkspace[4]; - byte driverWorkspace[12]; - byte immediateAddress[6]; - short fragCount; - short fragOff; - short fragSeg; - short fragSize; -} ECB; - -#pragma pack() - -typedef struct -{ - ECB ecb; - IPXheader header; - int sequence; - char data[NET_DATAGRAMSIZE]; -} ipx_lowmem_buffer_t; - -#define LOWMEMSIZE (100 * 1024) -#define LOWMEMSAVE 256 -#define IPXBUFFERS ((LOWMEMSIZE - LOWMEMSAVE)/ sizeof(ipx_lowmem_buffer_t)) -#define IPXSOCKBUFFERS 5 -#define IPXSOCKETS (IPXBUFFERS / IPXSOCKBUFFERS) - -// each socket's socketbuffer 0 is used for sending, the others for listening - -typedef struct -{ - char reserved[LOWMEMSAVE]; - ipx_lowmem_buffer_t socketbuffer[IPXSOCKETS][IPXSOCKBUFFERS]; -} ipx_lowmem_area_t; - - -static int ipxsocket[IPXSOCKETS]; -static ECB *readlist[IPXSOCKETS]; -static int sequence[IPXSOCKETS]; -static int handlesInUse; -static ipx_lowmem_area_t *lma; -static char *lowmem_buffer; -static int lowmem_bufseg; -static int lowmem_bufoff; -static unsigned short ipx_cs; -static unsigned short ipx_ip; -static int net_acceptsocket = -1; -static int net_controlsocket; - -static void IPX_PollProcedure(void); -static PollProcedure pollProcedure = {NULL, 0.0, IPX_PollProcedure}; - -//============================================================================= - -static void IPX_GetLocalAddress(IPXaddr *addr) -{ - regs.x.cs = ipx_cs; - regs.x.ip = ipx_ip; - regs.x.bx = IPX_GETADDRESS; - regs.x.es = lowmem_bufseg; - regs.x.si = lowmem_bufoff; - __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); - Q_memcpy(addr, lowmem_buffer, 10); -} - -//============================================================================= - -static int IPX_GetLocalTarget(IPXaddr *addr, byte *localTarget) -{ - regs.x.cs = ipx_cs; - regs.x.ip = ipx_ip; - regs.x.bx = IPX_GETROUTE; - regs.x.es = lowmem_bufseg; - regs.x.si = lowmem_bufoff; - regs.x.di = lowmem_bufoff + sizeof(IPXaddr); - Q_memcpy(lowmem_buffer, addr, sizeof(IPXaddr)); - __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); - if (regs.h.al) - return -1; - Q_memcpy(localTarget, lowmem_buffer + sizeof(IPXaddr), 6); - return 0; -} - -//============================================================================= - -static void IPX_ListenForPacket(ECB *ecb) -{ - regs.x.cs = ipx_cs; - regs.x.ip = ipx_ip; - regs.x.bx = IPX_LISTEN; - regs.x.es = ptr2real(ecb) >> 4; - regs.x.si = ptr2real(ecb) & 0xf; - __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); -} - -//============================================================================= - -static void IPX_RelinquishControl(void) -{ - regs.x.cs = ipx_cs; - regs.x.ip = ipx_ip; - regs.x.bx = IPX_RELINQUISH; - __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); -} - - -void IPX_PollProcedure(void) -{ - IPX_RelinquishControl(); - SchedulePollProcedure(&pollProcedure, 0.01); -} - -//============================================================================= - -static void ProcessReadyList(int s) -{ - int n; - ECB *ecb; - ECB *prev; - - for (n = 1; n < IPXSOCKBUFFERS; n++) - { - if (lma->socketbuffer[s][n].ecb.inUse == 0) - { - for (ecb = readlist[s], prev = NULL; ecb; ecb = ecb->link) - { - if (lma->socketbuffer[s][n].sequence < ((ipx_lowmem_buffer_t *) ecb)->sequence) - break; - prev = ecb; - } - if (ecb) - lma->socketbuffer[s][n].ecb.link = ecb; - else - lma->socketbuffer[s][n].ecb.link = NULL; - if (prev) - prev->link = &lma->socketbuffer[s][n].ecb; - else - readlist[s] = &lma->socketbuffer[s][n].ecb; - lma->socketbuffer[s][n].ecb.inUse = 0xff; - } - } -} - -//============================================================================= - -int IPX_Init(void) -{ - int s; - int n; - struct qsockaddr addr; - char *colon; - - if (COM_CheckParm ("-noipx")) - return -1; - - // find the IPX far call entry point - regs.x.ax = 0x7a00; - __dpmi_simulate_real_mode_interrupt (0x2f, (__dpmi_regs *)®s); - if (regs.h.al != 0xff) - { - Con_Printf("IPX not detected\n"); - return -1; - } - ipx_cs = regs.x.es; - ipx_ip = regs.x.di; - - // grab a chunk of memory down in DOS land - lowmem_buffer = dos_getmemory(LOWMEMSIZE); - if (!lowmem_buffer) - { - Con_Printf("IPX_Init: Not enough low memory\n"); - return -1; - } - lowmem_bufoff = ptr2real(lowmem_buffer) & 0xf; - lowmem_bufseg = ptr2real(lowmem_buffer) >> 4; - - // init socket handles & buffers - handlesInUse = 0; - lma = (ipx_lowmem_area_t *)lowmem_buffer; - for (s = 0; s < IPXSOCKETS; s++) - { - ipxsocket[s] = 0; - for (n = 0; n < IPXSOCKBUFFERS; n++) - { - lma->socketbuffer[s][n].ecb.link = NULL; - lma->socketbuffer[s][n].ecb.ESR_off = 0; - lma->socketbuffer[s][n].ecb.ESR_seg = 0; - lma->socketbuffer[s][n].ecb.socket = 0; - lma->socketbuffer[s][n].ecb.inUse = 0xff; - lma->socketbuffer[s][n].ecb.completionCode = 0; - lma->socketbuffer[s][n].ecb.fragCount = 1; - lma->socketbuffer[s][n].ecb.fragOff = ptr2real(&lma->socketbuffer[s][n].header) & 0xf; - lma->socketbuffer[s][n].ecb.fragSeg = ptr2real(&lma->socketbuffer[s][n].header) >> 4; - lma->socketbuffer[s][n].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE; - } - } - - if ((net_controlsocket = IPX_OpenSocket (0)) == -1) - { - dos_freememory(lowmem_buffer); - Con_DPrintf ("IPX_Init: Unable to open control socket\n"); - return -1; - } - - SchedulePollProcedure(&pollProcedure, 0.01); - - IPX_GetSocketAddr (net_controlsocket, &addr); - Q_strcpy(my_ipx_address, IPX_AddrToString (&addr)); - colon = Q_strrchr (my_ipx_address, ':'); - if (colon) - *colon = 0; - - Con_Printf("IPX initialized\n"); - ipxAvailable = true; - return net_controlsocket; -} - -//============================================================================= - -void IPX_Shutdown(void) -{ - IPX_Listen (false); - IPX_CloseSocket (net_controlsocket); - dos_freememory(lowmem_buffer); -} - -//============================================================================= - -void IPX_Listen (qboolean state) -{ - // enable listening - if (state) - { - if (net_acceptsocket != -1) - return; - if ((net_acceptsocket = IPX_OpenSocket (net_hostport)) == -1) - Sys_Error ("IPX_Listen: Unable to open accept socket\n"); - return; - } - - // disable listening - if (net_acceptsocket == -1) - return; - IPX_CloseSocket (net_acceptsocket); - net_acceptsocket = -1; -} - -//============================================================================= - -int IPX_OpenSocket(int port) -{ - int handle; - int n; - unsigned short socket; - - if (handlesInUse == IPXSOCKETS) - return -1; - - // open the IPX socket - regs.x.cs = ipx_cs; - regs.x.ip = ipx_ip; - regs.x.bx = IPX_OPEN; - regs.h.al = 0; - regs.x.dx = htons(port); - __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); - if (regs.h.al == 0xfe) - { - Con_DPrintf("IPX_OpenSocket: all sockets in use\n"); - return -1; - } - if (regs.h.al == 0xff) - { - Con_DPrintf("IPX_OpenSocket: socket already open\n"); - return -1; - } - if (regs.h.al != 0) - { - Con_DPrintf("IPX_OpenSocket: error %02x\n", regs.h.al); - return -1; - } - socket = regs.x.dx; - -// grab a handle; fill in the ECBs, and get them listening - for (handle = 0; handle < IPXSOCKETS; handle++) - { - if (ipxsocket[handle] == 0) - { - ipxsocket[handle] = socket; - readlist[handle] = NULL; - sequence[handle] = 0; - for (n = 0; n < IPXSOCKBUFFERS; n ++) - { - lma->socketbuffer[handle][n].ecb.socket = socket; - lma->socketbuffer[handle][n].ecb.inUse = 0; - if (n) - IPX_ListenForPacket(&lma->socketbuffer[handle][n].ecb); - } - handlesInUse++; - return handle; - } - } - - // "this will NEVER happen" - Sys_Error("IPX_OpenSocket: handle allocation failed\n"); - return -1; -} - -//============================================================================= - -int IPX_CloseSocket(int handle) -{ - // if there's a send in progress, give it one last chance - if (lma->socketbuffer[handle][0].ecb.inUse != 0) - IPX_RelinquishControl(); - - // close the socket (all pending sends/received are cancelled) - regs.x.cs = ipx_cs; - regs.x.ip = ipx_ip; - regs.x.bx = IPX_CLOSE; - regs.x.dx = ipxsocket[handle]; - __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); - - ipxsocket[handle] = 0; - handlesInUse--; - - return 0; -} - -//============================================================================= - -int IPX_Connect (int handle, struct qsockaddr *addr) -{ - IPXaddr ipxaddr; - - Q_memcpy(&ipxaddr, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr)); - if (IPX_GetLocalTarget(&ipxaddr, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0) - { - Con_Printf("Get Local Target failed\n"); - return -1; - } - - return 0; -} - -//============================================================================= - -int IPX_CheckNewConnections (void) -{ - int n; - - if (net_acceptsocket == -1) - return -1; - - for (n = 1; n < IPXSOCKBUFFERS; n ++) - if (lma->socketbuffer[net_acceptsocket][n].ecb.inUse == 0) - return net_acceptsocket; - return -1; -} - -//============================================================================= - -int IPX_Read (int handle, byte *buf, int len, struct qsockaddr *addr) -{ - ECB *ecb; - ipx_lowmem_buffer_t *rcvbuf; - int copylen; - - ProcessReadyList(handle); -tryagain: - if (readlist[handle] == NULL) - return 0; - ecb = readlist[handle]; - readlist[handle] = ecb->link; - - if (ecb->completionCode != 0) - { - Con_Printf("Warning: IPX_Read error %02x\n", ecb->completionCode); - ecb->fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE; - IPX_ListenForPacket(ecb); - goto tryagain; - } - - rcvbuf = (ipx_lowmem_buffer_t *)ecb; - - // copy the data up to the buffer - copylen = ntohs(rcvbuf->header.length) - (sizeof(int) + sizeof(IPXheader)); - if (len < copylen) - Sys_Error("IPX_Read: buffer too small (%d vs %d)\n", len, copylen); - Q_memcpy(buf, rcvbuf->data, copylen); - - // fill in the addr if they want it - if (addr) - { - ((struct sockaddr_ipx *)addr)->sipx_family = AF_NETWARE; - Q_memcpy(&((struct sockaddr_ipx *)addr)->sipx_addr, rcvbuf->header.source.network, sizeof(IPXaddr)); - ((struct sockaddr_ipx *)addr)->sipx_zero[0] = 0; - ((struct sockaddr_ipx *)addr)->sipx_zero[1] = 0; - } - - // update the send ecb's immediate address - Q_memcpy(lma->socketbuffer[handle][0].ecb.immediateAddress, rcvbuf->ecb.immediateAddress, 6); - - // get this ecb listening again - rcvbuf->ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE; - IPX_ListenForPacket(&rcvbuf->ecb); - return copylen; -} - -//============================================================================= - -int IPX_Broadcast (int handle, byte *buf, int len) -{ - struct sockaddr_ipx addr; - int ret; - - Q_memset(addr.sipx_addr.network, 0x00, 4); - Q_memset(addr.sipx_addr.node, 0xff, 6); - addr.sipx_port = htons(net_hostport); - Q_memset(lma->socketbuffer[handle][0].ecb.immediateAddress, 0xff, 6); - ret = IPX_Write (handle, buf, len, (struct qsockaddr *)&addr); - return ret; -} - -//============================================================================= - -int IPX_Write (int handle, byte *buf, int len, struct qsockaddr *addr) -{ - // has the previous send completed? - while (lma->socketbuffer[handle][0].ecb.inUse != 0) - IPX_RelinquishControl(); - - switch (lma->socketbuffer[handle][0].ecb.completionCode) - { - case 0x00: // success - case 0xfc: // request cancelled - break; - - case 0xfd: // malformed packet - default: - Con_Printf("IPX driver send failure: %02x\n", lma->socketbuffer[handle][0].ecb.completionCode); - break; - - case 0xfe: // packet undeliverable - case 0xff: // unable to send packet - Con_Printf("IPX lost route, trying to re-establish\n"); - - // look for a new route - if (IPX_GetLocalTarget (&lma->socketbuffer[handle][0].header.destination, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0) - return -1; - - // re-send the one that failed - regs.x.cs = ipx_cs; - regs.x.ip = ipx_ip; - regs.x.bx = IPX_SEND; - regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4; - regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf; - __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); - - // report that we did not send the current one - return 0; - } - - // ecb : length - lma->socketbuffer[handle][0].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + len; - - // ipx header : type - lma->socketbuffer[handle][0].header.type = PTYPE_IPX; - - // ipx header : destination - Q_memcpy(&lma->socketbuffer[handle][0].header.destination, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr)); - - // sequence number - lma->socketbuffer[handle][0].sequence = sequence[handle]; - sequence[handle]++; - - // copy down the data - Q_memcpy(lma->socketbuffer[handle][0].data, buf, len); - - regs.x.cs = ipx_cs; - regs.x.ip = ipx_ip; - regs.x.bx = IPX_SEND; - regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4; - regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf; - __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); - - return len; -} - -//============================================================================= - -char *IPX_AddrToString (struct qsockaddr *addr) -{ - static char buf[28]; - - sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u", - ((struct sockaddr_ipx *)addr)->sipx_addr.network[0], - ((struct sockaddr_ipx *)addr)->sipx_addr.network[1], - ((struct sockaddr_ipx *)addr)->sipx_addr.network[2], - ((struct sockaddr_ipx *)addr)->sipx_addr.network[3], - ((struct sockaddr_ipx *)addr)->sipx_addr.node[0], - ((struct sockaddr_ipx *)addr)->sipx_addr.node[1], - ((struct sockaddr_ipx *)addr)->sipx_addr.node[2], - ((struct sockaddr_ipx *)addr)->sipx_addr.node[3], - ((struct sockaddr_ipx *)addr)->sipx_addr.node[4], - ((struct sockaddr_ipx *)addr)->sipx_addr.node[5], - ntohs(((struct sockaddr_ipx *)addr)->sipx_port) - ); - return buf; -} - -//============================================================================= - -int IPX_StringToAddr (char *string, struct qsockaddr *addr) -{ - int val; - char buf[3]; - - buf[2] = 0; - Q_memset(addr, 0, sizeof(struct qsockaddr)); - addr->sa_family = AF_NETWARE; - -#define DO(src,dest) \ - buf[0] = string[src]; \ - buf[1] = string[src + 1]; \ - if (sscanf (buf, "%x", &val) != 1) \ - return -1; \ - ((struct sockaddr_ipx *)addr)->sipx_addr.dest = val - - DO(0, network[0]); - DO(2, network[1]); - DO(4, network[2]); - DO(6, network[3]); - DO(9, node[0]); - DO(11, node[1]); - DO(13, node[2]); - DO(15, node[3]); - DO(17, node[4]); - DO(19, node[5]); -#undef DO - - sscanf (&string[22], "%u", &val); - ((struct sockaddr_ipx *)addr)->sipx_port = htons(val); - - return 0; -} - -//============================================================================= - -int IPX_GetSocketAddr (int handle, struct qsockaddr *addr) -{ - Q_memset(addr, 0, sizeof(struct qsockaddr)); - addr->sa_family = AF_NETWARE; - IPX_GetLocalAddress(&((struct sockaddr_ipx *)addr)->sipx_addr); - ((struct sockaddr_ipx *)addr)->sipx_port = ipxsocket[handle]; - return 0; -} - -//============================================================================= - -int IPX_GetNameFromAddr (struct qsockaddr *addr, char *name) -{ - Q_strcpy(name, IPX_AddrToString(addr)); - return 0; -} - -//============================================================================= - -int IPX_GetAddrFromName (char *name, struct qsockaddr *addr) -{ - int n; - char buf[32]; - - n = Q_strlen(name); - - if (n == 12) - { - sprintf(buf, "00000000:%s:%u", name, net_hostport); - return IPX_StringToAddr (buf, addr); - } - if (n == 21) - { - sprintf(buf, "%s:%u", name, net_hostport); - return IPX_StringToAddr (buf, addr); - } - if (n > 21 && n <= 27) - return IPX_StringToAddr (name, addr); - - return -1; -} - -//============================================================================= - -int IPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) -{ - if (addr1->sa_family != addr2->sa_family) - return -1; - - if(Q_memcmp(&((struct sockaddr_ipx *)addr1)->sipx_addr, &((struct sockaddr_ipx *)addr2)->sipx_addr, 10)) - return -1; - - if (((struct sockaddr_ipx *)addr1)->sipx_port != ((struct sockaddr_ipx *)addr2)->sipx_port) - return 1; - - return 0; -} - -//============================================================================= - -int IPX_GetSocketPort (struct qsockaddr *addr) -{ - return ntohs(((struct sockaddr_ipx *)addr)->sipx_port); -} - - -int IPX_SetSocketPort (struct qsockaddr *addr, int port) -{ - ((struct sockaddr_ipx *)addr)->sipx_port = htons(port); - return 0; -} - -//============================================================================= +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_ipx.c + +#include +#include +#include + +#include "quakedef.h" +#include "dosisms.h" +#include "net_ipx.h" + +#define EIO 5 /* I/O error */ + +#define AF_NETWARE 64 + +#define IPX_OPEN 0 +#define IPX_CLOSE 1 +#define IPX_GETROUTE 2 +#define IPX_SEND 3 +#define IPX_LISTEN 4 +#define IPX_SCHEDULEEVENT 5 +#define IPX_CANCEL 6 +#define IPX_SCHEDULESPECIALEVENT 7 +#define IPX_GETINTERVALMARKER 8 +#define IPX_GETADDRESS 9 +#define IPX_RELINQUISH 10 + +#define PTYPE_UNKNOWN 0 +#define PTYPE_RIP 1 +#define PTYPE_ECHO 2 +#define PTYPE_ERROR 3 +#define PTYPE_IPX 4 +#define PTYPE_SPX 5 + +#pragma pack(1) + +typedef struct +{ + byte network[4]; + byte node[6]; + short socket; +} IPXaddr; + +struct sockaddr_ipx +{ + short sipx_family; + IPXaddr sipx_addr; + char sipx_zero[2]; +}; +#define sipx_port sipx_addr.socket + +typedef struct +{ + short checkSum; + short length; + byte transportControl; + byte type; + IPXaddr destination; + IPXaddr source; +} IPXheader; + +typedef struct ECBStructure +{ + struct ECBStructure *link; + unsigned short ESR_off; + unsigned short ESR_seg; + byte inUse; + byte completionCode; + short socket; + byte IPXWorkspace[4]; + byte driverWorkspace[12]; + byte immediateAddress[6]; + short fragCount; + short fragOff; + short fragSeg; + short fragSize; +} ECB; + +#pragma pack() + +typedef struct +{ + ECB ecb; + IPXheader header; + int sequence; + char data[NET_DATAGRAMSIZE]; +} ipx_lowmem_buffer_t; + +#define LOWMEMSIZE (100 * 1024) +#define LOWMEMSAVE 256 +#define IPXBUFFERS ((LOWMEMSIZE - LOWMEMSAVE)/ sizeof(ipx_lowmem_buffer_t)) +#define IPXSOCKBUFFERS 5 +#define IPXSOCKETS (IPXBUFFERS / IPXSOCKBUFFERS) + +// each socket's socketbuffer 0 is used for sending, the others for listening + +typedef struct +{ + char reserved[LOWMEMSAVE]; + ipx_lowmem_buffer_t socketbuffer[IPXSOCKETS][IPXSOCKBUFFERS]; +} ipx_lowmem_area_t; + + +static int ipxsocket[IPXSOCKETS]; +static ECB *readlist[IPXSOCKETS]; +static int sequence[IPXSOCKETS]; +static int handlesInUse; +static ipx_lowmem_area_t *lma; +static char *lowmem_buffer; +static int lowmem_bufseg; +static int lowmem_bufoff; +static unsigned short ipx_cs; +static unsigned short ipx_ip; +static int net_acceptsocket = -1; +static int net_controlsocket; + +static void IPX_PollProcedure(void); +static PollProcedure pollProcedure = {NULL, 0.0, IPX_PollProcedure}; + +//============================================================================= + +static void IPX_GetLocalAddress(IPXaddr *addr) +{ + regs.x.cs = ipx_cs; + regs.x.ip = ipx_ip; + regs.x.bx = IPX_GETADDRESS; + regs.x.es = lowmem_bufseg; + regs.x.si = lowmem_bufoff; + __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); + Q_memcpy(addr, lowmem_buffer, 10); +} + +//============================================================================= + +static int IPX_GetLocalTarget(IPXaddr *addr, byte *localTarget) +{ + regs.x.cs = ipx_cs; + regs.x.ip = ipx_ip; + regs.x.bx = IPX_GETROUTE; + regs.x.es = lowmem_bufseg; + regs.x.si = lowmem_bufoff; + regs.x.di = lowmem_bufoff + sizeof(IPXaddr); + Q_memcpy(lowmem_buffer, addr, sizeof(IPXaddr)); + __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); + if (regs.h.al) + return -1; + Q_memcpy(localTarget, lowmem_buffer + sizeof(IPXaddr), 6); + return 0; +} + +//============================================================================= + +static void IPX_ListenForPacket(ECB *ecb) +{ + regs.x.cs = ipx_cs; + regs.x.ip = ipx_ip; + regs.x.bx = IPX_LISTEN; + regs.x.es = ptr2real(ecb) >> 4; + regs.x.si = ptr2real(ecb) & 0xf; + __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); +} + +//============================================================================= + +static void IPX_RelinquishControl(void) +{ + regs.x.cs = ipx_cs; + regs.x.ip = ipx_ip; + regs.x.bx = IPX_RELINQUISH; + __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); +} + + +void IPX_PollProcedure(void) +{ + IPX_RelinquishControl(); + SchedulePollProcedure(&pollProcedure, 0.01); +} + +//============================================================================= + +static void ProcessReadyList(int s) +{ + int n; + ECB *ecb; + ECB *prev; + + for (n = 1; n < IPXSOCKBUFFERS; n++) + { + if (lma->socketbuffer[s][n].ecb.inUse == 0) + { + for (ecb = readlist[s], prev = NULL; ecb; ecb = ecb->link) + { + if (lma->socketbuffer[s][n].sequence < ((ipx_lowmem_buffer_t *) ecb)->sequence) + break; + prev = ecb; + } + if (ecb) + lma->socketbuffer[s][n].ecb.link = ecb; + else + lma->socketbuffer[s][n].ecb.link = NULL; + if (prev) + prev->link = &lma->socketbuffer[s][n].ecb; + else + readlist[s] = &lma->socketbuffer[s][n].ecb; + lma->socketbuffer[s][n].ecb.inUse = 0xff; + } + } +} + +//============================================================================= + +int IPX_Init(void) +{ + int s; + int n; + struct qsockaddr addr; + char *colon; + + if (COM_CheckParm ("-noipx")) + return -1; + + // find the IPX far call entry point + regs.x.ax = 0x7a00; + __dpmi_simulate_real_mode_interrupt (0x2f, (__dpmi_regs *)®s); + if (regs.h.al != 0xff) + { + Con_Printf("IPX not detected\n"); + return -1; + } + ipx_cs = regs.x.es; + ipx_ip = regs.x.di; + + // grab a chunk of memory down in DOS land + lowmem_buffer = dos_getmemory(LOWMEMSIZE); + if (!lowmem_buffer) + { + Con_Printf("IPX_Init: Not enough low memory\n"); + return -1; + } + lowmem_bufoff = ptr2real(lowmem_buffer) & 0xf; + lowmem_bufseg = ptr2real(lowmem_buffer) >> 4; + + // init socket handles & buffers + handlesInUse = 0; + lma = (ipx_lowmem_area_t *)lowmem_buffer; + for (s = 0; s < IPXSOCKETS; s++) + { + ipxsocket[s] = 0; + for (n = 0; n < IPXSOCKBUFFERS; n++) + { + lma->socketbuffer[s][n].ecb.link = NULL; + lma->socketbuffer[s][n].ecb.ESR_off = 0; + lma->socketbuffer[s][n].ecb.ESR_seg = 0; + lma->socketbuffer[s][n].ecb.socket = 0; + lma->socketbuffer[s][n].ecb.inUse = 0xff; + lma->socketbuffer[s][n].ecb.completionCode = 0; + lma->socketbuffer[s][n].ecb.fragCount = 1; + lma->socketbuffer[s][n].ecb.fragOff = ptr2real(&lma->socketbuffer[s][n].header) & 0xf; + lma->socketbuffer[s][n].ecb.fragSeg = ptr2real(&lma->socketbuffer[s][n].header) >> 4; + lma->socketbuffer[s][n].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE; + } + } + + if ((net_controlsocket = IPX_OpenSocket (0)) == -1) + { + dos_freememory(lowmem_buffer); + Con_DPrintf ("IPX_Init: Unable to open control socket\n"); + return -1; + } + + SchedulePollProcedure(&pollProcedure, 0.01); + + IPX_GetSocketAddr (net_controlsocket, &addr); + Q_strcpy(my_ipx_address, IPX_AddrToString (&addr)); + colon = Q_strrchr (my_ipx_address, ':'); + if (colon) + *colon = 0; + + Con_Printf("IPX initialized\n"); + ipxAvailable = true; + return net_controlsocket; +} + +//============================================================================= + +void IPX_Shutdown(void) +{ + IPX_Listen (false); + IPX_CloseSocket (net_controlsocket); + dos_freememory(lowmem_buffer); +} + +//============================================================================= + +void IPX_Listen (qboolean state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + if ((net_acceptsocket = IPX_OpenSocket (net_hostport)) == -1) + Sys_Error ("IPX_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + IPX_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} + +//============================================================================= + +int IPX_OpenSocket(int port) +{ + int handle; + int n; + unsigned short socket; + + if (handlesInUse == IPXSOCKETS) + return -1; + + // open the IPX socket + regs.x.cs = ipx_cs; + regs.x.ip = ipx_ip; + regs.x.bx = IPX_OPEN; + regs.h.al = 0; + regs.x.dx = htons(port); + __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); + if (regs.h.al == 0xfe) + { + Con_DPrintf("IPX_OpenSocket: all sockets in use\n"); + return -1; + } + if (regs.h.al == 0xff) + { + Con_DPrintf("IPX_OpenSocket: socket already open\n"); + return -1; + } + if (regs.h.al != 0) + { + Con_DPrintf("IPX_OpenSocket: error %02x\n", regs.h.al); + return -1; + } + socket = regs.x.dx; + +// grab a handle; fill in the ECBs, and get them listening + for (handle = 0; handle < IPXSOCKETS; handle++) + { + if (ipxsocket[handle] == 0) + { + ipxsocket[handle] = socket; + readlist[handle] = NULL; + sequence[handle] = 0; + for (n = 0; n < IPXSOCKBUFFERS; n ++) + { + lma->socketbuffer[handle][n].ecb.socket = socket; + lma->socketbuffer[handle][n].ecb.inUse = 0; + if (n) + IPX_ListenForPacket(&lma->socketbuffer[handle][n].ecb); + } + handlesInUse++; + return handle; + } + } + + // "this will NEVER happen" + Sys_Error("IPX_OpenSocket: handle allocation failed\n"); + return -1; +} + +//============================================================================= + +int IPX_CloseSocket(int handle) +{ + // if there's a send in progress, give it one last chance + if (lma->socketbuffer[handle][0].ecb.inUse != 0) + IPX_RelinquishControl(); + + // close the socket (all pending sends/received are cancelled) + regs.x.cs = ipx_cs; + regs.x.ip = ipx_ip; + regs.x.bx = IPX_CLOSE; + regs.x.dx = ipxsocket[handle]; + __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); + + ipxsocket[handle] = 0; + handlesInUse--; + + return 0; +} + +//============================================================================= + +int IPX_Connect (int handle, struct qsockaddr *addr) +{ + IPXaddr ipxaddr; + + Q_memcpy(&ipxaddr, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr)); + if (IPX_GetLocalTarget(&ipxaddr, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0) + { + Con_Printf("Get Local Target failed\n"); + return -1; + } + + return 0; +} + +//============================================================================= + +int IPX_CheckNewConnections (void) +{ + int n; + + if (net_acceptsocket == -1) + return -1; + + for (n = 1; n < IPXSOCKBUFFERS; n ++) + if (lma->socketbuffer[net_acceptsocket][n].ecb.inUse == 0) + return net_acceptsocket; + return -1; +} + +//============================================================================= + +int IPX_Read (int handle, byte *buf, int len, struct qsockaddr *addr) +{ + ECB *ecb; + ipx_lowmem_buffer_t *rcvbuf; + int copylen; + + ProcessReadyList(handle); +tryagain: + if (readlist[handle] == NULL) + return 0; + ecb = readlist[handle]; + readlist[handle] = ecb->link; + + if (ecb->completionCode != 0) + { + Con_Printf("Warning: IPX_Read error %02x\n", ecb->completionCode); + ecb->fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE; + IPX_ListenForPacket(ecb); + goto tryagain; + } + + rcvbuf = (ipx_lowmem_buffer_t *)ecb; + + // copy the data up to the buffer + copylen = ntohs(rcvbuf->header.length) - (sizeof(int) + sizeof(IPXheader)); + if (len < copylen) + Sys_Error("IPX_Read: buffer too small (%d vs %d)\n", len, copylen); + Q_memcpy(buf, rcvbuf->data, copylen); + + // fill in the addr if they want it + if (addr) + { + ((struct sockaddr_ipx *)addr)->sipx_family = AF_NETWARE; + Q_memcpy(&((struct sockaddr_ipx *)addr)->sipx_addr, rcvbuf->header.source.network, sizeof(IPXaddr)); + ((struct sockaddr_ipx *)addr)->sipx_zero[0] = 0; + ((struct sockaddr_ipx *)addr)->sipx_zero[1] = 0; + } + + // update the send ecb's immediate address + Q_memcpy(lma->socketbuffer[handle][0].ecb.immediateAddress, rcvbuf->ecb.immediateAddress, 6); + + // get this ecb listening again + rcvbuf->ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE; + IPX_ListenForPacket(&rcvbuf->ecb); + return copylen; +} + +//============================================================================= + +int IPX_Broadcast (int handle, byte *buf, int len) +{ + struct sockaddr_ipx addr; + int ret; + + Q_memset(addr.sipx_addr.network, 0x00, 4); + Q_memset(addr.sipx_addr.node, 0xff, 6); + addr.sipx_port = htons(net_hostport); + Q_memset(lma->socketbuffer[handle][0].ecb.immediateAddress, 0xff, 6); + ret = IPX_Write (handle, buf, len, (struct qsockaddr *)&addr); + return ret; +} + +//============================================================================= + +int IPX_Write (int handle, byte *buf, int len, struct qsockaddr *addr) +{ + // has the previous send completed? + while (lma->socketbuffer[handle][0].ecb.inUse != 0) + IPX_RelinquishControl(); + + switch (lma->socketbuffer[handle][0].ecb.completionCode) + { + case 0x00: // success + case 0xfc: // request cancelled + break; + + case 0xfd: // malformed packet + default: + Con_Printf("IPX driver send failure: %02x\n", lma->socketbuffer[handle][0].ecb.completionCode); + break; + + case 0xfe: // packet undeliverable + case 0xff: // unable to send packet + Con_Printf("IPX lost route, trying to re-establish\n"); + + // look for a new route + if (IPX_GetLocalTarget (&lma->socketbuffer[handle][0].header.destination, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0) + return -1; + + // re-send the one that failed + regs.x.cs = ipx_cs; + regs.x.ip = ipx_ip; + regs.x.bx = IPX_SEND; + regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4; + regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf; + __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); + + // report that we did not send the current one + return 0; + } + + // ecb : length + lma->socketbuffer[handle][0].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + len; + + // ipx header : type + lma->socketbuffer[handle][0].header.type = PTYPE_IPX; + + // ipx header : destination + Q_memcpy(&lma->socketbuffer[handle][0].header.destination, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr)); + + // sequence number + lma->socketbuffer[handle][0].sequence = sequence[handle]; + sequence[handle]++; + + // copy down the data + Q_memcpy(lma->socketbuffer[handle][0].data, buf, len); + + regs.x.cs = ipx_cs; + regs.x.ip = ipx_ip; + regs.x.bx = IPX_SEND; + regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4; + regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf; + __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s); + + return len; +} + +//============================================================================= + +char *IPX_AddrToString (struct qsockaddr *addr) +{ + static char buf[28]; + + sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u", + ((struct sockaddr_ipx *)addr)->sipx_addr.network[0], + ((struct sockaddr_ipx *)addr)->sipx_addr.network[1], + ((struct sockaddr_ipx *)addr)->sipx_addr.network[2], + ((struct sockaddr_ipx *)addr)->sipx_addr.network[3], + ((struct sockaddr_ipx *)addr)->sipx_addr.node[0], + ((struct sockaddr_ipx *)addr)->sipx_addr.node[1], + ((struct sockaddr_ipx *)addr)->sipx_addr.node[2], + ((struct sockaddr_ipx *)addr)->sipx_addr.node[3], + ((struct sockaddr_ipx *)addr)->sipx_addr.node[4], + ((struct sockaddr_ipx *)addr)->sipx_addr.node[5], + ntohs(((struct sockaddr_ipx *)addr)->sipx_port) + ); + return buf; +} + +//============================================================================= + +int IPX_StringToAddr (char *string, struct qsockaddr *addr) +{ + int val; + char buf[3]; + + buf[2] = 0; + Q_memset(addr, 0, sizeof(struct qsockaddr)); + addr->sa_family = AF_NETWARE; + +#define DO(src,dest) \ + buf[0] = string[src]; \ + buf[1] = string[src + 1]; \ + if (sscanf (buf, "%x", &val) != 1) \ + return -1; \ + ((struct sockaddr_ipx *)addr)->sipx_addr.dest = val + + DO(0, network[0]); + DO(2, network[1]); + DO(4, network[2]); + DO(6, network[3]); + DO(9, node[0]); + DO(11, node[1]); + DO(13, node[2]); + DO(15, node[3]); + DO(17, node[4]); + DO(19, node[5]); +#undef DO + + sscanf (&string[22], "%u", &val); + ((struct sockaddr_ipx *)addr)->sipx_port = htons(val); + + return 0; +} + +//============================================================================= + +int IPX_GetSocketAddr (int handle, struct qsockaddr *addr) +{ + Q_memset(addr, 0, sizeof(struct qsockaddr)); + addr->sa_family = AF_NETWARE; + IPX_GetLocalAddress(&((struct sockaddr_ipx *)addr)->sipx_addr); + ((struct sockaddr_ipx *)addr)->sipx_port = ipxsocket[handle]; + return 0; +} + +//============================================================================= + +int IPX_GetNameFromAddr (struct qsockaddr *addr, char *name) +{ + Q_strcpy(name, IPX_AddrToString(addr)); + return 0; +} + +//============================================================================= + +int IPX_GetAddrFromName (char *name, struct qsockaddr *addr) +{ + int n; + char buf[32]; + + n = Q_strlen(name); + + if (n == 12) + { + sprintf(buf, "00000000:%s:%u", name, net_hostport); + return IPX_StringToAddr (buf, addr); + } + if (n == 21) + { + sprintf(buf, "%s:%u", name, net_hostport); + return IPX_StringToAddr (buf, addr); + } + if (n > 21 && n <= 27) + return IPX_StringToAddr (name, addr); + + return -1; +} + +//============================================================================= + +int IPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if(Q_memcmp(&((struct sockaddr_ipx *)addr1)->sipx_addr, &((struct sockaddr_ipx *)addr2)->sipx_addr, 10)) + return -1; + + if (((struct sockaddr_ipx *)addr1)->sipx_port != ((struct sockaddr_ipx *)addr2)->sipx_port) + return 1; + + return 0; +} + +//============================================================================= + +int IPX_GetSocketPort (struct qsockaddr *addr) +{ + return ntohs(((struct sockaddr_ipx *)addr)->sipx_port); +} + + +int IPX_SetSocketPort (struct qsockaddr *addr, int port) +{ + ((struct sockaddr_ipx *)addr)->sipx_port = htons(port); + return 0; +} + +//============================================================================= -- cgit v1.2.3