|
|
1.1 root 1: // net_ipx.c
2:
3: #include <stdio.h>
4: #include <stdlib.h>
5: #include <dpmi.h>
6:
7: #include "quakedef.h"
8: #include "dosisms.h"
9: #include "net_ipx.h"
10:
11: #define EIO 5 /* I/O error */
12:
13: #define AF_NETWARE 64
14:
15: #define IPX_OPEN 0
16: #define IPX_CLOSE 1
17: #define IPX_GETROUTE 2
18: #define IPX_SEND 3
19: #define IPX_LISTEN 4
20: #define IPX_SCHEDULEEVENT 5
21: #define IPX_CANCEL 6
22: #define IPX_SCHEDULESPECIALEVENT 7
23: #define IPX_GETINTERVALMARKER 8
24: #define IPX_GETADDRESS 9
25: #define IPX_RELINQUISH 10
26:
27: #define PTYPE_UNKNOWN 0
28: #define PTYPE_RIP 1
29: #define PTYPE_ECHO 2
30: #define PTYPE_ERROR 3
31: #define PTYPE_IPX 4
32: #define PTYPE_SPX 5
33:
34: #pragma pack(1)
35:
36: typedef struct
37: {
38: byte network[4];
39: byte node[6];
40: short socket;
41: } IPXaddr;
42:
43: struct sockaddr_ipx
44: {
45: short sipx_family;
46: IPXaddr sipx_addr;
47: char sipx_zero[2];
48: };
49: #define sipx_port sipx_addr.socket
50:
51: typedef struct
52: {
53: short checkSum;
54: short length;
55: byte transportControl;
56: byte type;
57: IPXaddr destination;
58: IPXaddr source;
59: } IPXheader;
60:
61: typedef struct ECBStructure
62: {
63: struct ECBStructure *link;
64: unsigned short ESR_off;
65: unsigned short ESR_seg;
66: byte inUse;
67: byte completionCode;
68: short socket;
69: byte IPXWorkspace[4];
70: byte driverWorkspace[12];
71: byte immediateAddress[6];
72: short fragCount;
73: short fragOff;
74: short fragSeg;
75: short fragSize;
76: } ECB;
77:
78: #pragma pack()
79:
80: typedef struct
81: {
82: ECB ecb;
83: IPXheader header;
84: int sequence;
85: char data[NET_DATAGRAMSIZE];
86: } ipx_lowmem_buffer_t;
87:
88: #define LOWMEMSIZE (100 * 1024)
89: #define LOWMEMSAVE 256
90: #define IPXBUFFERS ((LOWMEMSIZE - LOWMEMSAVE)/ sizeof(ipx_lowmem_buffer_t))
91: #define IPXSOCKBUFFERS 5
92: #define IPXSOCKETS (IPXBUFFERS / IPXSOCKBUFFERS)
93:
94: // each socket's socketbuffer 0 is used for sending, the others for listening
95:
96: typedef struct
97: {
98: char reserved[LOWMEMSAVE];
99: ipx_lowmem_buffer_t socketbuffer[IPXSOCKETS][IPXSOCKBUFFERS];
100: } ipx_lowmem_area_t;
101:
102:
103: static int ipxsocket[IPXSOCKETS];
104: static ECB *readlist[IPXSOCKETS];
105: static int sequence[IPXSOCKETS];
106: static int handlesInUse;
107: static ipx_lowmem_area_t *lma;
108: static char *lowmem_buffer;
109: static int lowmem_bufseg;
110: static int lowmem_bufoff;
111: static unsigned short ipx_cs;
112: static unsigned short ipx_ip;
113: static int net_acceptsocket = -1;
114: static int net_controlsocket;
115:
116: static void IPX_PollProcedure(void);
117: static PollProcedure pollProcedure = {NULL, 0.0, IPX_PollProcedure};
118:
119: //=============================================================================
120:
121: static void IPX_GetLocalAddress(IPXaddr *addr)
122: {
123: regs.x.cs = ipx_cs;
124: regs.x.ip = ipx_ip;
125: regs.x.bx = IPX_GETADDRESS;
126: regs.x.es = lowmem_bufseg;
127: regs.x.si = lowmem_bufoff;
128: __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
129: Q_memcpy(addr, lowmem_buffer, 10);
130: }
131:
132: //=============================================================================
133:
134: static int IPX_GetLocalTarget(IPXaddr *addr, byte *localTarget)
135: {
136: regs.x.cs = ipx_cs;
137: regs.x.ip = ipx_ip;
138: regs.x.bx = IPX_GETROUTE;
139: regs.x.es = lowmem_bufseg;
140: regs.x.si = lowmem_bufoff;
141: regs.x.di = lowmem_bufoff + sizeof(IPXaddr);
142: Q_memcpy(lowmem_buffer, addr, sizeof(IPXaddr));
143: __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
144: if (regs.h.al)
145: return -1;
146: Q_memcpy(localTarget, lowmem_buffer + sizeof(IPXaddr), 6);
147: return 0;
148: }
149:
150: //=============================================================================
151:
152: static void IPX_ListenForPacket(ECB *ecb)
153: {
154: regs.x.cs = ipx_cs;
155: regs.x.ip = ipx_ip;
156: regs.x.bx = IPX_LISTEN;
157: regs.x.es = ptr2real(ecb) >> 4;
158: regs.x.si = ptr2real(ecb) & 0xf;
159: __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
160: }
161:
162: //=============================================================================
163:
164: static void IPX_RelinquishControl(void)
165: {
166: regs.x.cs = ipx_cs;
167: regs.x.ip = ipx_ip;
168: regs.x.bx = IPX_RELINQUISH;
169: __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
170: }
171:
172:
173: void IPX_PollProcedure(void)
174: {
175: IPX_RelinquishControl();
176: SchedulePollProcedure(&pollProcedure, 0.01);
177: }
178:
179: //=============================================================================
180:
181: static void ProcessReadyList(int s)
182: {
183: int n;
184: ECB *ecb;
185: ECB *prev;
186:
187: for (n = 1; n < IPXSOCKBUFFERS; n++)
188: {
189: if (lma->socketbuffer[s][n].ecb.inUse == 0)
190: {
191: for (ecb = readlist[s], prev = NULL; ecb; ecb = ecb->link)
192: {
193: if (lma->socketbuffer[s][n].sequence < ((ipx_lowmem_buffer_t *) ecb)->sequence)
194: break;
195: prev = ecb;
196: }
197: if (ecb)
198: lma->socketbuffer[s][n].ecb.link = ecb;
199: else
200: lma->socketbuffer[s][n].ecb.link = NULL;
201: if (prev)
202: prev->link = &lma->socketbuffer[s][n].ecb;
203: else
204: readlist[s] = &lma->socketbuffer[s][n].ecb;
205: lma->socketbuffer[s][n].ecb.inUse = 0xff;
206: }
207: }
208: }
209:
210: //=============================================================================
211:
212: int IPX_Init(void)
213: {
214: int s;
215: int n;
216: struct qsockaddr addr;
217: char *colon;
218:
219: if (COM_CheckParm ("-noipx"))
220: return -1;
221:
222: // find the IPX far call entry point
223: regs.x.ax = 0x7a00;
224: __dpmi_simulate_real_mode_interrupt (0x2f, (__dpmi_regs *)®s);
225: if (regs.h.al != 0xff)
226: {
227: Con_Printf("IPX not detected\n");
228: return -1;
229: }
230: ipx_cs = regs.x.es;
231: ipx_ip = regs.x.di;
232:
233: // grab a chunk of memory down in DOS land
234: lowmem_buffer = dos_getmemory(LOWMEMSIZE);
235: if (!lowmem_buffer)
236: {
237: Con_Printf("IPX_Init: Not enough low memory\n");
238: return -1;
239: }
240: lowmem_bufoff = ptr2real(lowmem_buffer) & 0xf;
241: lowmem_bufseg = ptr2real(lowmem_buffer) >> 4;
242:
243: // init socket handles & buffers
244: handlesInUse = 0;
245: lma = (ipx_lowmem_area_t *)lowmem_buffer;
246: for (s = 0; s < IPXSOCKETS; s++)
247: {
248: ipxsocket[s] = 0;
249: for (n = 0; n < IPXSOCKBUFFERS; n++)
250: {
251: lma->socketbuffer[s][n].ecb.link = NULL;
252: lma->socketbuffer[s][n].ecb.ESR_off = 0;
253: lma->socketbuffer[s][n].ecb.ESR_seg = 0;
254: lma->socketbuffer[s][n].ecb.socket = 0;
255: lma->socketbuffer[s][n].ecb.inUse = 0xff;
256: lma->socketbuffer[s][n].ecb.completionCode = 0;
257: lma->socketbuffer[s][n].ecb.fragCount = 1;
258: lma->socketbuffer[s][n].ecb.fragOff = ptr2real(&lma->socketbuffer[s][n].header) & 0xf;
259: lma->socketbuffer[s][n].ecb.fragSeg = ptr2real(&lma->socketbuffer[s][n].header) >> 4;
260: lma->socketbuffer[s][n].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
261: }
262: }
263:
264: if ((net_controlsocket = IPX_OpenSocket (0)) == -1)
265: {
266: dos_freememory(lowmem_buffer);
267: Con_DPrintf ("IPX_Init: Unable to open control socket\n");
268: return -1;
269: }
270:
271: SchedulePollProcedure(&pollProcedure, 0.01);
272:
273: IPX_GetSocketAddr (net_controlsocket, &addr);
274: Q_strcpy(my_ipx_address, IPX_AddrToString (&addr));
275: colon = Q_strrchr (my_ipx_address, ':');
276: if (colon)
277: *colon = 0;
278:
279: Con_Printf("IPX initialized\n");
280: ipxAvailable = true;
281: return net_controlsocket;
282: }
283:
284: //=============================================================================
285:
286: void IPX_Shutdown(void)
287: {
288: IPX_Listen (false);
289: IPX_CloseSocket (net_controlsocket);
290: dos_freememory(lowmem_buffer);
291: }
292:
293: //=============================================================================
294:
295: void IPX_Listen (qboolean state)
296: {
297: // enable listening
298: if (state)
299: {
300: if (net_acceptsocket != -1)
301: return;
302: if ((net_acceptsocket = IPX_OpenSocket (net_hostport)) == -1)
303: Sys_Error ("IPX_Listen: Unable to open accept socket\n");
304: return;
305: }
306:
307: // disable listening
308: if (net_acceptsocket == -1)
309: return;
310: IPX_CloseSocket (net_acceptsocket);
311: net_acceptsocket = -1;
312: }
313:
314: //=============================================================================
315:
316: int IPX_OpenSocket(int port)
317: {
318: int handle;
319: int n;
320: unsigned short socket;
321:
322: if (handlesInUse == IPXSOCKETS)
323: return -1;
324:
325: // open the IPX socket
326: regs.x.cs = ipx_cs;
327: regs.x.ip = ipx_ip;
328: regs.x.bx = IPX_OPEN;
329: regs.h.al = 0;
330: regs.x.dx = htons(port);
331: __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
332: if (regs.h.al == 0xfe)
333: {
334: Con_DPrintf("IPX_OpenSocket: all sockets in use\n");
335: return -1;
336: }
337: if (regs.h.al == 0xff)
338: {
339: Con_DPrintf("IPX_OpenSocket: socket already open\n");
340: return -1;
341: }
342: if (regs.h.al != 0)
343: {
344: Con_DPrintf("IPX_OpenSocket: error %02x\n", regs.h.al);
345: return -1;
346: }
347: socket = regs.x.dx;
348:
349: // grab a handle; fill in the ECBs, and get them listening
350: for (handle = 0; handle < IPXSOCKETS; handle++)
351: {
352: if (ipxsocket[handle] == 0)
353: {
354: ipxsocket[handle] = socket;
355: readlist[handle] = NULL;
356: sequence[handle] = 0;
357: for (n = 0; n < IPXSOCKBUFFERS; n ++)
358: {
359: lma->socketbuffer[handle][n].ecb.socket = socket;
360: lma->socketbuffer[handle][n].ecb.inUse = 0;
361: if (n)
362: IPX_ListenForPacket(&lma->socketbuffer[handle][n].ecb);
363: }
364: handlesInUse++;
365: return handle;
366: }
367: }
368:
369: // "this will NEVER happen"
370: Sys_Error("IPX_OpenSocket: handle allocation failed\n");
371: return -1;
372: }
373:
374: //=============================================================================
375:
376: int IPX_CloseSocket(int handle)
377: {
378: // if there's a send in progress, give it one last chance
379: if (lma->socketbuffer[handle][0].ecb.inUse != 0)
380: IPX_RelinquishControl();
381:
382: // close the socket (all pending sends/received are cancelled)
383: regs.x.cs = ipx_cs;
384: regs.x.ip = ipx_ip;
385: regs.x.bx = IPX_CLOSE;
386: regs.x.dx = ipxsocket[handle];
387: __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
388:
389: ipxsocket[handle] = 0;
390: handlesInUse--;
391:
392: return 0;
393: }
394:
395: //=============================================================================
396:
397: int IPX_Connect (int handle, struct qsockaddr *addr)
398: {
399: IPXaddr ipxaddr;
400:
401: Q_memcpy(&ipxaddr, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr));
402: if (IPX_GetLocalTarget(&ipxaddr, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0)
403: {
404: Con_Printf("Get Local Target failed\n");
405: return -1;
406: }
407:
408: return 0;
409: }
410:
411: //=============================================================================
412:
413: int IPX_CheckNewConnections (void)
414: {
415: int n;
416:
417: if (net_acceptsocket == -1)
418: return -1;
419:
420: for (n = 1; n < IPXSOCKBUFFERS; n ++)
421: if (lma->socketbuffer[net_acceptsocket][n].ecb.inUse == 0)
422: return net_acceptsocket;
423: return -1;
424: }
425:
426: //=============================================================================
427:
428: int IPX_Read (int handle, byte *buf, int len, struct qsockaddr *addr)
429: {
430: ECB *ecb;
431: ipx_lowmem_buffer_t *rcvbuf;
432: int copylen;
433:
434: ProcessReadyList(handle);
435: tryagain:
436: if (readlist[handle] == NULL)
437: return 0;
438: ecb = readlist[handle];
439: readlist[handle] = ecb->link;
440:
441: if (ecb->completionCode != 0)
442: {
443: Con_Printf("Warning: IPX_Read error %02x\n", ecb->completionCode);
444: ecb->fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
445: IPX_ListenForPacket(ecb);
446: goto tryagain;
447: }
448:
449: rcvbuf = (ipx_lowmem_buffer_t *)ecb;
450:
451: // copy the data up to the buffer
452: copylen = ntohs(rcvbuf->header.length) - (sizeof(int) + sizeof(IPXheader));
453: if (len < copylen)
454: Sys_Error("IPX_Read: buffer too small (%d vs %d)\n", len, copylen);
455: Q_memcpy(buf, rcvbuf->data, copylen);
456:
457: // fill in the addr if they want it
458: if (addr)
459: {
460: ((struct sockaddr_ipx *)addr)->sipx_family = AF_NETWARE;
461: Q_memcpy(&((struct sockaddr_ipx *)addr)->sipx_addr, rcvbuf->header.source.network, sizeof(IPXaddr));
462: ((struct sockaddr_ipx *)addr)->sipx_zero[0] = 0;
463: ((struct sockaddr_ipx *)addr)->sipx_zero[1] = 0;
464: }
465:
466: // update the send ecb's immediate address
467: Q_memcpy(lma->socketbuffer[handle][0].ecb.immediateAddress, rcvbuf->ecb.immediateAddress, 6);
468:
469: // get this ecb listening again
470: rcvbuf->ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
471: IPX_ListenForPacket(&rcvbuf->ecb);
472: return copylen;
473: }
474:
475: //=============================================================================
476:
477: int IPX_Broadcast (int handle, byte *buf, int len)
478: {
479: struct sockaddr_ipx addr;
480: int ret;
481:
482: Q_memset(addr.sipx_addr.network, 0x00, 4);
483: Q_memset(addr.sipx_addr.node, 0xff, 6);
484: addr.sipx_port = htons(net_hostport);
485: Q_memset(lma->socketbuffer[handle][0].ecb.immediateAddress, 0xff, 6);
486: ret = IPX_Write (handle, buf, len, (struct qsockaddr *)&addr);
487: return ret;
488: }
489:
490: //=============================================================================
491:
492: int IPX_Write (int handle, byte *buf, int len, struct qsockaddr *addr)
493: {
494: // has the previous send completed?
495: while (lma->socketbuffer[handle][0].ecb.inUse != 0)
496: IPX_RelinquishControl();
497:
498: switch (lma->socketbuffer[handle][0].ecb.completionCode)
499: {
500: case 0x00: // success
501: case 0xfc: // request cancelled
502: break;
503:
504: case 0xfd: // malformed packet
505: default:
506: Con_Printf("IPX driver send failure: %02x\n", lma->socketbuffer[handle][0].ecb.completionCode);
507: break;
508:
509: case 0xfe: // packet undeliverable
510: case 0xff: // unable to send packet
511: Con_Printf("IPX lost route, trying to re-establish\n");
512:
513: // look for a new route
514: if (IPX_GetLocalTarget (&lma->socketbuffer[handle][0].header.destination, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0)
515: return -1;
516:
517: // re-send the one that failed
518: regs.x.cs = ipx_cs;
519: regs.x.ip = ipx_ip;
520: regs.x.bx = IPX_SEND;
521: regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4;
522: regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf;
523: __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
524:
525: // report that we did not send the current one
526: return 0;
527: }
528:
529: // ecb : length
530: lma->socketbuffer[handle][0].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + len;
531:
532: // ipx header : type
533: lma->socketbuffer[handle][0].header.type = PTYPE_IPX;
534:
535: // ipx header : destination
536: Q_memcpy(&lma->socketbuffer[handle][0].header.destination, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr));
537:
538: // sequence number
539: lma->socketbuffer[handle][0].sequence = sequence[handle];
540: sequence[handle]++;
541:
542: // copy down the data
543: Q_memcpy(lma->socketbuffer[handle][0].data, buf, len);
544:
545: regs.x.cs = ipx_cs;
546: regs.x.ip = ipx_ip;
547: regs.x.bx = IPX_SEND;
548: regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4;
549: regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf;
550: __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
551:
552: return len;
553: }
554:
555: //=============================================================================
556:
557: char *IPX_AddrToString (struct qsockaddr *addr)
558: {
559: static char buf[28];
560:
561: sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u",
562: ((struct sockaddr_ipx *)addr)->sipx_addr.network[0],
563: ((struct sockaddr_ipx *)addr)->sipx_addr.network[1],
564: ((struct sockaddr_ipx *)addr)->sipx_addr.network[2],
565: ((struct sockaddr_ipx *)addr)->sipx_addr.network[3],
566: ((struct sockaddr_ipx *)addr)->sipx_addr.node[0],
567: ((struct sockaddr_ipx *)addr)->sipx_addr.node[1],
568: ((struct sockaddr_ipx *)addr)->sipx_addr.node[2],
569: ((struct sockaddr_ipx *)addr)->sipx_addr.node[3],
570: ((struct sockaddr_ipx *)addr)->sipx_addr.node[4],
571: ((struct sockaddr_ipx *)addr)->sipx_addr.node[5],
572: ntohs(((struct sockaddr_ipx *)addr)->sipx_port)
573: );
574: return buf;
575: }
576:
577: //=============================================================================
578:
579: int IPX_StringToAddr (char *string, struct qsockaddr *addr)
580: {
581: int val;
582: char buf[3];
583:
584: buf[2] = 0;
585: Q_memset(addr, 0, sizeof(struct qsockaddr));
586: addr->sa_family = AF_NETWARE;
587:
588: #define DO(src,dest) \
589: buf[0] = string[src]; \
590: buf[1] = string[src + 1]; \
591: if (sscanf (buf, "%x", &val) != 1) \
592: return -1; \
593: ((struct sockaddr_ipx *)addr)->sipx_addr.dest = val
594:
595: DO(0, network[0]);
596: DO(2, network[1]);
597: DO(4, network[2]);
598: DO(6, network[3]);
599: DO(9, node[0]);
600: DO(11, node[1]);
601: DO(13, node[2]);
602: DO(15, node[3]);
603: DO(17, node[4]);
604: DO(19, node[5]);
605: #undef DO
606:
607: sscanf (&string[22], "%u", &val);
608: ((struct sockaddr_ipx *)addr)->sipx_port = htons(val);
609:
610: return 0;
611: }
612:
613: //=============================================================================
614:
615: int IPX_GetSocketAddr (int handle, struct qsockaddr *addr)
616: {
617: Q_memset(addr, 0, sizeof(struct qsockaddr));
618: addr->sa_family = AF_NETWARE;
619: IPX_GetLocalAddress(&((struct sockaddr_ipx *)addr)->sipx_addr);
620: ((struct sockaddr_ipx *)addr)->sipx_port = ipxsocket[handle];
621: return 0;
622: }
623:
624: //=============================================================================
625:
626: int IPX_GetNameFromAddr (struct qsockaddr *addr, char *name)
627: {
628: Q_strcpy(name, IPX_AddrToString(addr));
629: return 0;
630: }
631:
632: //=============================================================================
633:
634: int IPX_GetAddrFromName (char *name, struct qsockaddr *addr)
635: {
636: int n;
637: char buf[32];
638:
639: n = Q_strlen(name);
640:
641: if (n == 12)
642: {
643: sprintf(buf, "00000000:%s:%u", name, net_hostport);
644: return IPX_StringToAddr (buf, addr);
645: }
646: if (n == 21)
647: {
648: sprintf(buf, "%s:%u", name, net_hostport);
649: return IPX_StringToAddr (buf, addr);
650: }
651: if (n > 21 && n <= 27)
652: return IPX_StringToAddr (name, addr);
653:
654: return -1;
655: }
656:
657: //=============================================================================
658:
659: int IPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
660: {
661: if (addr1->sa_family != addr2->sa_family)
662: return -1;
663:
664: if(Q_memcmp(&((struct sockaddr_ipx *)addr1)->sipx_addr, &((struct sockaddr_ipx *)addr2)->sipx_addr, 10))
665: return -1;
666:
667: if (((struct sockaddr_ipx *)addr1)->sipx_port != ((struct sockaddr_ipx *)addr2)->sipx_port)
668: return 1;
669:
670: return 0;
671: }
672:
673: //=============================================================================
674:
675: int IPX_GetSocketPort (struct qsockaddr *addr)
676: {
677: return ntohs(((struct sockaddr_ipx *)addr)->sipx_port);
678: }
679:
680:
681: int IPX_SetSocketPort (struct qsockaddr *addr, int port)
682: {
683: ((struct sockaddr_ipx *)addr)->sipx_port = htons(port);
684: return 0;
685: }
686:
687: //=============================================================================
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.