CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

IPX.CPP (53275B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /* $Header:   F:\projects\c&c\vcs\code\ipx.cpv   2.17   16 Oct 1995 16:49:34   JOE_BOSTIC  $ */
     17 /***************************************************************************
     18  **   C O N F I D E N T I A L --- W E S T W O O D    S T U D I O S        **
     19  ***************************************************************************
     20  *                                                                         *
     21  *                 Project Name : Command & Conquer                        *
     22  *                                                                         *
     23  *                    File Name : IPX.CPP                                  *
     24  *                                                                         *
     25  *                   Programmer : Barry Nance										*
     26  * 										 from Client/Server LAN Programming			*
     27  *											 Westwood-ized by Bill Randolph				*
     28  *                                                                         *
     29  *                   Start Date : December 14, 1994                        *
     30  *                                                                         *
     31  *                  Last Update : December 15, 1994   [BR]                 *
     32  *                                                                         *
     33  *-------------------------------------------------------------------------*
     34  * Pitfalls:																					*
     35  * - Never try to use a closed socket; always check the return code from	*
     36  *   IPX_Open_Socket().																		*
     37  * - Always give IPX an outstanding ECB for listening, before you send.		*
     38  * - It turns out that IPX is pretty bad about saving registers, so if		*
     39  *   you have any register variables in your program, they may get			*
     40  *   trashed.  To circumvent this, all functions in this module save &		*
     41  *   restore the registers before invoking any IPX or NETX function.			*
     42  *                                                                         *
     43  *-------------------------------------------------------------------------*
     44  * Functions:                                                              *
     45  *   IPX_SPX_Installed -- checks for installation of IPX/SPX               *
     46  *   IPX_Open_Socket -- opens an IPX socket for sending or receiving       *
     47  *   IPX_Close_Socket -- closes an open socket                             *
     48  *   IPX_Get_Connection_Number -- gets local Connection Number					*
     49  *   IPX_Get_1st_Connection_Num -- gets 1st Connect Number for given user  *
     50  *   IPX_Get_Internet_Address -- gets Network Number & Node Address			*
     51  *   IPX_Get_User_ID -- gets user ID from Connection Number                *
     52  *   IPX_Listen_For_Packet -- commands IPX to listen for a packet          *
     53  *   IPX_Send_Packet -- commands IPX to send a packet                      *
     54  *   IPX_Get_Local_Target -- fills in ImmediateAddress field of ECB        *
     55  *   IPX_Cancel_Event -- cancels an operation in progress                  *
     56  *   Let_IPX_Breath -- gives IPX some CPU time                             *
     57  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     58 
     59 #include "function.h"
     60 #include "ipx95.h"
     61 
     62 
     63 /***************************************************************************
     64  * IPX_SPX_Installed -- checks for installation of IPX/SPX                 *
     65  *                                                                         *
     66  * INPUT:                                                                  *
     67  *		none.																						*
     68  *                                                                         *
     69  * OUTPUT:                                                                 *
     70  *		0 = not installed; 1 = IPX only, 2 = IPX and SPX are installed			*
     71  *                                                                         *
     72  * WARNINGS:                                                               *
     73  *		none.																						*
     74  *                                                                         *
     75  * HISTORY:                                                                *
     76  *   12/14/1994 BR : Created.                                              *
     77  *=========================================================================*/
     78 int IPX_SPX_Installed(void)
     79 {
     80 
     81 #ifndef NOT_FOR_WIN95
     82 
     83 	return (IPX_Initialise());
     84 
     85 #else	//NOT_FOR_WIN95
     86 
     87 	union REGS regs;
     88 	struct SREGS sregs;
     89 	RMIType rmi;
     90 
     91 	/*------------------------------------------------------------------------
     92 	Init all registers to 0's
     93 	------------------------------------------------------------------------*/
     94 	memset (&regs, 0 ,sizeof(regs));
     95 	segread (&sregs);
     96 	memset (&rmi, 0 ,sizeof(rmi));
     97 
     98 	/*------------------------------------------------------------------------
     99 	Fill in registers for the DPMI call, function 0x300
    100 	------------------------------------------------------------------------*/
    101 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    102 	regs.w.bx = 0x002f;					// interrupt # to invoke
    103 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    104 	regs.x.edi = FP_OFF(&rmi);
    105 
    106 	/*------------------------------------------------------------------------
    107 	Fill in registers for the real-mode interrupt handler.
    108 	To test for the presence of IPX, set AH to 0x7a, AL to 0, and invoke
    109 	interrupt 0x2f (the "multiplex" interrupt).  If IPX is installed,
    110 	AL will be 0xff, and ES:DI will contain the IPX/SPX function address.
    111 	------------------------------------------------------------------------*/
    112 	rmi.eax = 0x00007a00;
    113 
    114 	/*------------------------------------------------------------------------
    115 	call DPMI
    116 	------------------------------------------------------------------------*/
    117 	int386x(DPMI_INT, &regs, &regs, &sregs);
    118 
    119 	/*------------------------------------------------------------------------
    120 	If IPX isn't there, return 0
    121 	------------------------------------------------------------------------*/
    122 	if ( (rmi.eax & 0x00ff) != 0xff) {
    123 		return(0);
    124 	}
    125 
    126 	/*------------------------------------------------------------------------
    127 	Test for SPX by invoking the IPX_SPX function with BX = 0x10, and AL = 0.
    128 	If SPX is present, AL will be 0xff.
    129 	------------------------------------------------------------------------*/
    130 	/*........................................................................
    131 	Fill in registers for the DPMI call
    132 	........................................................................*/
    133 	memset (&regs, 0 ,sizeof(regs));
    134 	segread (&sregs);
    135 	memset (&rmi, 0 ,sizeof(rmi));
    136 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    137 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    138 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    139 	regs.x.edi = FP_OFF(&rmi);
    140 	/*........................................................................
    141 	Fill in registers for the interrupt call
    142 	........................................................................*/
    143 	rmi.ebx = 0x00000010;
    144 	/*........................................................................
    145 	call DPMI
    146 	........................................................................*/
    147 	int386x(DPMI_INT, &regs, &regs, &sregs);
    148 
    149 	/*------------------------------------------------------------------------
    150 	SPX is installed; return '2'
    151 	------------------------------------------------------------------------*/
    152 	if ( (rmi.eax & 0x00ff) == 0xff) {
    153 		return(2);
    154 	}
    155 
    156 	/*------------------------------------------------------------------------
    157 	SPX is not installed; return '1'
    158 	------------------------------------------------------------------------*/
    159 	return(1);
    160 #endif	//NOT_FOR_WIN95
    161 }	/* end of IPX_SPX_Installed */
    162 
    163 
    164 /***************************************************************************
    165  * IPX_Open_Socket -- opens an IPX socket for sending or receiving         *
    166  *                                                                         *
    167  * INPUT:                                                                  *
    168  *		socket		the socket number to open											*
    169  *                                                                         *
    170  * OUTPUT:                                                                 *
    171  *		0 = OK																					*
    172  *		-1 = IPX not installed																*
    173  *		0xfe = socket table is full														*
    174  *		0xff = socket is already open														*
    175  *                                                                         *
    176  * WARNINGS:                                                               *
    177  *		The application must define its socket number carefully.  Use			*
    178  *		values from 0x4000 to 0x8000 for custom socket numbers.  The app		*
    179  *		must know its own socket number as well as the socket number of		*
    180  *		a destination workstation.															*
    181  *                                                                         *
    182  * HISTORY:                                                                *
    183  *   12/15/1994 BR : Created.                                              *
    184  *=========================================================================*/
    185 #ifdef NOT_FOR_WIN95
    186 int IPX_Open_Socket(unsigned short socket)
    187 {
    188 	union REGS regs;
    189 	struct SREGS sregs;
    190 	RMIType rmi;
    191 	int rc;
    192 
    193 	/*------------------------------------------------------------------------
    194 	Open the socket:
    195 	DX = socket number
    196 	AL = 0 for short-lived socket, 0xff for long-lived socket
    197 	------------------------------------------------------------------------*/
    198 	/*........................................................................
    199 	Fill in registers for the DPMI call
    200 	........................................................................*/
    201 	memset (&regs, 0 ,sizeof(regs));
    202 	segread (&sregs);
    203 	memset (&rmi, 0 ,sizeof(rmi));
    204 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    205 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    206 	sregs.es = FP_SEG (&rmi);			// tell DPMI where the RMI is
    207 	regs.x.edi = FP_OFF (&rmi);
    208 	/*........................................................................
    209 	Fill in registers for the interrupt call
    210 	........................................................................*/
    211 	rmi.ebx = IPX_OPEN_SOCKET;			// function code
    212 	rmi.edx = socket;						// desired socket #
    213 	rmi.eax = 0x00ff;						// make this a long-lived socket
    214 	/*........................................................................
    215 	call DPMI
    216 	........................................................................*/
    217 	int386x (DPMI_INT, &regs, &regs, &sregs);
    218 
    219 	rc = (rmi.eax & 0xff);
    220 
    221 	return(rc);
    222 
    223 }	/* end of IPX_Open_Socket */
    224 
    225 #endif
    226 /***************************************************************************
    227  * IPX_Close_Socket -- closes an open socket                               *
    228  *                                                                         *
    229  * INPUT:                                                                  *
    230  *		socket		socket number to close												*
    231  *                                                                         *
    232  * OUTPUT:                                                                 *
    233  *		0 = ok, -1 = error																	*
    234  *                                                                         *
    235  * WARNINGS:                                                               *
    236  *		none.																						*
    237  *                                                                         *
    238  * HISTORY:                                                                *
    239  *   12/15/1994 BR : Created.                                              *
    240  *=========================================================================*/
    241 #ifdef NOT_FOR_WIN95
    242 int IPX_Close_Socket(unsigned short socket)
    243 {
    244 	union REGS regs;
    245 	struct SREGS sregs;
    246 	RMIType rmi;
    247 
    248 	/*------------------------------------------------------------------------
    249 	Close the socket:
    250 	DX = socket number
    251 	------------------------------------------------------------------------*/
    252 	/*........................................................................
    253 	Fill in registers for the DPMI call
    254 	........................................................................*/
    255 	memset (&regs, 0 ,sizeof(regs));
    256 	segread (&sregs);
    257 	memset (&rmi, 0 ,sizeof(rmi));
    258 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    259 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    260 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    261 	regs.x.edi = FP_OFF(&rmi);
    262 	/*........................................................................
    263 	Fill in registers for the interrupt call
    264 	........................................................................*/
    265 	rmi.ebx = IPX_CLOSE_SOCKET;
    266 	rmi.edx = socket;
    267 	/*........................................................................
    268 	call DPMI
    269 	........................................................................*/
    270 	int386x(DPMI_INT, &regs, &regs, &sregs);
    271 
    272 	return(0);
    273 
    274 }	/* end of IPX_Close_Socket */
    275 #endif	//NOT_FOR_WIN95
    276 
    277 /***************************************************************************
    278  * IPX_Get_Connection_Number -- gets local Connection Number					*
    279  *                                                                         *
    280  * This Novell call will the return the user's local "Connection Number".	*
    281  * This value will be 0 if the user isn't logged into Novell, so this		*
    282  * routine can be used to detect if other calls (such as Get_Local_Target)	*
    283  * will be OK.																					*
    284  *                                                                         *
    285  * INPUT:                                                                  *
    286  *		none.																						*
    287  *                                                                         *
    288  * OUTPUT:                                                                 *
    289  *		Connection Number, 0 = none														*
    290  *                                                                         *
    291  * WARNINGS:                                                               *
    292  *		none.																						*
    293  *                                                                         *
    294  * HISTORY:                                                                *
    295  *   12/15/1994 BR : Created.                                              *
    296  *=========================================================================*/
    297 #ifdef NOT_FOR_WIN95
    298 int IPX_Get_Connection_Number(void)
    299 {
    300 	union REGS regs;
    301 	struct SREGS sregs;
    302 	RMIType rmi;
    303 	int num;
    304 
    305 	/*------------------------------------------------------------------------
    306 	Call Interrupt 0x21, with AH = 0xdc.  This tells Novell to put the local
    307 	connection number into AL.
    308 	------------------------------------------------------------------------*/
    309 	/*........................................................................
    310 	Fill in registers for the DPMI call
    311 	........................................................................*/
    312 	memset (&regs, 0 ,sizeof(regs));
    313 	segread (&sregs);
    314 	memset (&rmi, 0 ,sizeof(rmi));
    315 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    316 	regs.w.bx = 0x21;						// interrupt # to invoke
    317 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    318 	regs.x.edi = FP_OFF(&rmi);
    319 	/*........................................................................
    320 	Fill in registers for the interrupt call
    321 	........................................................................*/
    322 	rmi.eax = 0x0000dc00;
    323 	/*........................................................................
    324 	call DPMI
    325 	........................................................................*/
    326 	int386x(DPMI_INT, &regs, &regs, &sregs);
    327 
    328 	num = rmi.eax & 0x00ff;
    329 
    330 	return(num);
    331 
    332 }	/* end of IPX_Get_Connection_Number */
    333 
    334 #endif //NOT_FOR_WIN95
    335 
    336 /***************************************************************************
    337  * IPX_Get_1st_Connection_Num -- gets 1st Connect Number for given user    *
    338  *                                                                         *
    339  * This gets the Connection Number for the given User ID.  Since a user		*
    340  * may be logged in more than once, this just returns the first connection	*
    341  * found and ignores the others.															*
    342  *                                                                         *
    343  * INPUT:                                                                  *
    344  *		username		name of the user to get the Connection Number for			*
    345  *                                                                         *
    346  * OUTPUT:                                                                 *
    347  *		first-found Connection Number for that user, 0 if user not logged in	*
    348  *                                                                         *
    349  * WARNINGS:                                                               *
    350  *                                                                         *
    351  * HISTORY:                                                                *
    352  *   12/15/1994 BR : Created.                                              *
    353  *=========================================================================*/
    354 #ifdef NOT_FOR_WIN95
    355 int IPX_Get_1st_Connection_Num (char *username)
    356 {
    357 	struct request_buffer {
    358 		unsigned short len;							// username length + 5
    359 		unsigned char buffer_type;					// ConnectionNum = 0x15
    360 		unsigned short object_type;				// set ot 0x0100
    361 		unsigned char name_len;						// length of username
    362 		char name [48];								// copy of username
    363 		unsigned short reserved;
    364 	};
    365 	struct reply_buffer {
    366 		unsigned short  len;
    367 		unsigned char   number_connections;		// will be 0 - 100
    368 		unsigned char   connection_num [100];	// array of connection numbers
    369 		unsigned short  reserved[2];
    370 	};
    371 	union REGS regs;
    372 	struct SREGS sregs;
    373 	RMIType rmi;
    374 	struct request_buffer *reqbuf;
    375 	struct reply_buffer *replybuf;
    376 	unsigned short segment;							// for DOS allocation
    377 	unsigned short selector;						// for DOS allocation
    378 	int num_conns;										// # connections returned
    379 	int conn_num;										// connection number
    380 	int rc;
    381 
    382 	/*------------------------------------------------------------------------
    383 	Allocate DOS memory to store the buffers passed to the interrupt
    384 	------------------------------------------------------------------------*/
    385 	memset (&regs, 0 ,sizeof(regs));
    386 	segread (&sregs);
    387 	regs.x.eax = DPMI_ALLOC_DOS_MEM;						// DPMI function to call
    388 	regs.x.ebx = (sizeof(struct request_buffer) + 	// # paragraphs to allocate
    389 		sizeof(struct reply_buffer) + 15) >> 4;
    390 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    391 	/*........................................................................
    392 	If the carry flag is set, DPMI is indicating an error.
    393 	........................................................................*/
    394 	if (regs.x.cflag) {
    395 		return(0);
    396 	}
    397 
    398 	/*........................................................................
    399 	Get pointers to allocated memory.
    400 	'reqbuf' is just the returned real-mode segment, multiplied by 16.
    401 	'replybuf' is an offset from 'reqbuf'.
    402 	........................................................................*/
    403 	segment = regs.w.ax;
    404 	selector = regs.w.dx;
    405 	reqbuf = (struct request_buffer *)(segment << 4);
    406 	replybuf = (struct reply_buffer *)
    407 		(((char *)reqbuf) + sizeof (struct request_buffer));
    408 
    409 	/*------------------------------------------------------------------------
    410 	Init the contents of the request & reply buffers
    411 	------------------------------------------------------------------------*/
    412 	reqbuf->len = (unsigned short)(strlen(username) + 5);
    413 	reqbuf->buffer_type = 0x15;
    414 	reqbuf->object_type = 0x0100;
    415 	reqbuf->name_len    = (unsigned char) strlen(username);
    416 	strcpy(reqbuf->name, username);
    417 	reqbuf->reserved = reqbuf->reserved;				// prevent compiler warning
    418 	replybuf->len = 101;
    419 	replybuf->reserved[0] = replybuf->reserved[0];	// prevent compiler warning
    420 	replybuf->reserved[0] = replybuf->reserved[1];	// prevent compiler warning
    421 
    422 	/*------------------------------------------------------------------------
    423 	Invoke Int 21 with AH=0xe3, DS:SI=&request_buffer, ES:DI=&reply_buffer
    424 	------------------------------------------------------------------------*/
    425 	/*........................................................................
    426 	Fill in registers for the DPMI call
    427 	........................................................................*/
    428 	memset (&regs, 0 ,sizeof(regs));
    429 	segread (&sregs);
    430 	memset (&rmi, 0 ,sizeof(rmi));
    431 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    432 	regs.w.bx = 0x21;						// interrupt # to invoke
    433 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    434 	regs.x.edi = FP_OFF(&rmi);
    435 	/*........................................................................
    436 	Fill in registers for the interrupt call
    437 	........................................................................*/
    438 	rmi.eax = 0x0000e300;
    439 	rmi.ds = segment;
    440 	rmi.esi = 0;
    441 	rmi.es = segment;
    442 	rmi.edi = sizeof(struct request_buffer);
    443 	/*........................................................................
    444 	call DPMI
    445 	........................................................................*/
    446 	int386x(DPMI_INT, &regs, &regs, &sregs);
    447 
    448 	/*------------------------------------------------------------------------
    449 	Stash the 1st connection number
    450 	------------------------------------------------------------------------*/
    451 	rc = (rmi.eax & 0x00ff);								// if AL !=0, error
    452 	num_conns = replybuf->number_connections;			// # times user is logged in
    453 	conn_num = (int )replybuf->connection_num[0];	// 1st connection #
    454 
    455 	/*------------------------------------------------------------------------
    456 	Free DOS memory
    457 	------------------------------------------------------------------------*/
    458 	memset (&regs, 0 ,sizeof(regs));
    459 	segread (&sregs);
    460 	regs.x.eax = DPMI_FREE_DOS_MEM;						// DPMI function to call
    461 	regs.x.edx = selector;									// ptr to free
    462 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    463 
    464 	/*------------------------------------------------------------------------
    465 	Return error if function failed, or user not logged in
    466 	------------------------------------------------------------------------*/
    467 	if (rc != 0 || num_conns==0) {
    468 		return(0);
    469 	} else {
    470 		return(conn_num);
    471 	}
    472 }
    473 #endif	//NOT_FOR_WIN95
    474 
    475 /***************************************************************************
    476  * IPX_Get_Internet_Address -- gets Network Number & Node Address				*
    477  *                                                                         *
    478  * Once you've obtained a Connection Number from IPX_Get_Connection_Number	*
    479  * or IPX_Get_1st_Connection_Num, use this function to translate it into	*
    480  * a Network Number and Node Address; then, place those numbers in the		*
    481  * IPX header for outgoing packets.														*
    482  *                                                                         *
    483  * INPUT:                                                                  *
    484  *		connection_number		Connection Number to translate						*
    485  *		network_number			ptr: will hold Network Number							*
    486  *		physical_node			ptr: will hold Node Address							*
    487  *                                                                         *
    488  * OUTPUT:                                                                 *
    489  *		0 = OK, -1 = error																	*
    490  *                                                                         *
    491  * WARNINGS:                                                               *
    492  *		If connection_number is 0 and NETX isn't running, this routine			*
    493  *		will just put garbage into the network_number and physical_node.		*
    494  *                                                                         *
    495  * HISTORY:                                                                *
    496  *   12/15/1994 BR : Created.                                              *
    497  *=========================================================================*/
    498 #ifdef NOT_FOR_WIN95
    499 int IPX_Get_Internet_Address(int connection_number,
    500 	unsigned char *network_number, unsigned char *physical_node)
    501 {
    502 	struct request_buffer {
    503 		unsigned short  len;
    504 		unsigned char   buffer_type;				// Internet = 0x13
    505 		unsigned char   connection_number;		// Conn. Number to translate
    506 	};
    507 	struct reply_buffer {
    508 		unsigned short  len;
    509 		unsigned char   network_number [4];		// filled in by IPX
    510 		unsigned char   physical_node  [6];		// filled in by IPX
    511 		unsigned short  server_socket;			// filled in by IPX, but don't use!
    512 	};
    513 	union REGS regs;
    514 	struct SREGS sregs;
    515 	RMIType rmi;
    516 	struct request_buffer *reqbuf;
    517 	struct reply_buffer *replybuf;
    518 	unsigned short segment;							// for DOS allocation
    519 	unsigned short selector;						// for DOS allocation
    520 
    521 	/*------------------------------------------------------------------------
    522 	Error if invalid connection is given
    523 	------------------------------------------------------------------------*/
    524 	if (connection_number==0)
    525 		return(-1);
    526 
    527 	/*------------------------------------------------------------------------
    528 	Allocate DOS memory to store the buffers passed to the interrupt
    529 	------------------------------------------------------------------------*/
    530 	memset (&regs, 0 ,sizeof(regs));
    531 	segread (&sregs);
    532 	regs.x.eax = DPMI_ALLOC_DOS_MEM;						// DPMI function to call
    533 	regs.x.ebx = (sizeof(struct request_buffer) + 	// # paragraphs to allocate
    534 		sizeof(struct reply_buffer) + 15) >> 4;
    535 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    536 	/*........................................................................
    537 	If the carry flag is set, DPMI is indicating an error.
    538 	........................................................................*/
    539 	if (regs.x.cflag) {
    540 		return(-1);
    541 	}
    542 
    543 	/*........................................................................
    544 	Get pointers to allocated memory.
    545 	'reqbuf' is just the returned real-mode segment, multiplied by 16.
    546 	'replybuf' is an offset from 'reqbuf'.
    547 	........................................................................*/
    548 	segment = regs.w.ax;
    549 	selector = regs.w.dx;
    550 	reqbuf = (struct request_buffer *)(segment << 4);
    551 	replybuf = (struct reply_buffer *)
    552 		(((char *)reqbuf) + sizeof (struct request_buffer));
    553 
    554 	/*------------------------------------------------------------------------
    555 	Init the contents of the request & reply buffers
    556 	------------------------------------------------------------------------*/
    557 	reqbuf->len = 2;
    558 	reqbuf->buffer_type = 0x13;
    559 	reqbuf->connection_number = (unsigned char)connection_number;
    560 	replybuf->len = 12;
    561 	replybuf->network_number[0] = replybuf->network_number[0];	// suppress warning
    562 	replybuf->physical_node[0] = replybuf->physical_node[0];		// suppress warning
    563 	replybuf->server_socket = replybuf->server_socket;				// suppress warning
    564 
    565 	/*------------------------------------------------------------------------
    566 	Invoke Int 21 with AH=0xe3, DS:SI=&request_buffer, ES:DI=&reply_buffer
    567 	------------------------------------------------------------------------*/
    568 	/*........................................................................
    569 	Fill in registers for the DPMI call
    570 	........................................................................*/
    571 	memset (&regs, 0 ,sizeof(regs));
    572 	segread (&sregs);
    573 	memset (&rmi, 0 ,sizeof(rmi));
    574 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    575 	regs.w.bx = 0x21;						// interrupt # to invoke
    576 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    577 	regs.x.edi = FP_OFF(&rmi);
    578 	/*........................................................................
    579 	Fill in registers for the interrupt call
    580 	........................................................................*/
    581 	rmi.eax = 0x0000e300;
    582 	rmi.ds = segment;
    583 	rmi.esi = 0;
    584 	rmi.es = segment;
    585 	rmi.edi = sizeof(struct request_buffer);
    586 	/*........................................................................
    587 	call DPMI
    588 	........................................................................*/
    589 	int386x(DPMI_INT, &regs, &regs, &sregs);
    590 
    591 	memcpy(network_number, replybuf->network_number, 4);
    592 	memcpy(physical_node,  replybuf->physical_node,  6);
    593 
    594 	/*------------------------------------------------------------------------
    595 	Free DOS memory
    596 	------------------------------------------------------------------------*/
    597 	memset (&regs, 0 ,sizeof(regs));
    598 	segread (&sregs);
    599 	regs.x.eax = DPMI_FREE_DOS_MEM;						// DPMI function to call
    600 	regs.x.edx = selector;									// ptr to free
    601 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    602 
    603 	return(0);
    604 
    605 }	/* end of IPX_Get_Internet_Address */
    606 
    607 #endif	// NOT_FOR_WIN95
    608 
    609 /***************************************************************************
    610  * IPX_Get_User_ID -- gets user ID from Connection Number                  *
    611  *                                                                         *
    612  * INPUT:                                                                  *
    613  *		connection_number		Connection Number to get User ID for				*
    614  *		user_id					ptr to buffer to put User ID into; 					*
    615  *									size must be >= 48 chars								*
    616  *                                                                         *
    617  * OUTPUT:                                                                 *
    618  *		0 = OK, -1 = error																	*
    619  *                                                                         *
    620  * WARNINGS:                                                               *
    621  *		none.																						*
    622  *                                                                         *
    623  * HISTORY:                                                                *
    624  *   12/15/1994 BR : Created.                                              *
    625  *=========================================================================*/
    626 #ifdef NOT_FOR_WIN95
    627 int IPX_Get_User_ID(int connection_number, char *user_id)
    628 {
    629 	struct request_buffer {
    630 		unsigned short  len;
    631 		unsigned char   buffer_type;			// 0x16 = UserID buffer type
    632 		unsigned char   connection_number;	// Connection Number to get ID for
    633 	};
    634 	struct reply_buffer {
    635 		unsigned short  len;
    636 		unsigned char   object_id[4];
    637 		unsigned char   object_type[2];
    638 		char            object_name[48];
    639 		char            login_time[7];
    640 		unsigned short  reserved;
    641 	};
    642 	union REGS      regs;
    643 	struct SREGS    sregs;
    644 	RMIType rmi;
    645 	struct request_buffer *reqbuf;
    646 	struct reply_buffer *replybuf;
    647 	unsigned short segment;							// for DOS allocation
    648 	unsigned short selector;						// for DOS allocation
    649 
    650 	/*------------------------------------------------------------------------
    651 	Error if invalid connection is given
    652 	------------------------------------------------------------------------*/
    653 	if (connection_number==0)
    654 		return(-1);
    655 
    656 	/*------------------------------------------------------------------------
    657 	Allocate DOS memory to store the buffers passed to the interrupt
    658 	------------------------------------------------------------------------*/
    659 	memset (&regs, 0 ,sizeof(regs));
    660 	segread (&sregs);
    661 	regs.x.eax = DPMI_ALLOC_DOS_MEM;						// DPMI function to call
    662 	regs.x.ebx = (sizeof(struct request_buffer) + 	// # paragraphs to allocate
    663 		sizeof(struct reply_buffer) + 15) >> 4;
    664 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    665 	/*........................................................................
    666 	If the carry flag is set, DPMI is indicating an error.
    667 	........................................................................*/
    668 	if (regs.x.cflag) {
    669 		return(-1);
    670 	}
    671 
    672 	/*........................................................................
    673 	Get pointers to allocated memory.
    674 	'reqbuf' is just the returned real-mode segment, multiplied by 16.
    675 	'replybuf' is an offset from 'reqbuf'.
    676 	........................................................................*/
    677 	segment = regs.w.ax;
    678 	selector = regs.w.dx;
    679 	reqbuf = (struct request_buffer *)(segment << 4);
    680 	replybuf = (struct reply_buffer *)
    681 		(((char *)reqbuf) + sizeof (struct request_buffer));
    682 
    683 	/*------------------------------------------------------------------------
    684 	Init the contents of the request & reply buffers
    685 	------------------------------------------------------------------------*/
    686 	reqbuf->len = 2;
    687 	reqbuf->buffer_type = 0x16;
    688 	reqbuf->connection_number = (unsigned char)connection_number;
    689 	replybuf->len = sizeof(struct reply_buffer) - 2;
    690 	replybuf->object_id[0] = replybuf->object_id[0];		// suppress warnings
    691 	replybuf->object_type[0] = replybuf->object_type[0];	// suppress warnings
    692 	replybuf->login_time[0] = replybuf->login_time[0];		// suppress warnings
    693 	replybuf->reserved = replybuf->reserved;					// suppress warnings
    694 
    695 	/*------------------------------------------------------------------------
    696 	Invoke Int 21 with AH=0xe3, DS:SI=&request_buffer, ES:DI=&reply_buffer
    697 	------------------------------------------------------------------------*/
    698 	/*........................................................................
    699 	Fill in registers for the DPMI call
    700 	........................................................................*/
    701 	memset (&regs, 0 ,sizeof(regs));
    702 	segread (&sregs);
    703 	memset (&rmi, 0 ,sizeof(rmi));
    704 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    705 	regs.w.bx = 0x21;						// interrupt # to invoke
    706 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    707 	regs.x.edi = FP_OFF(&rmi);
    708 	/*........................................................................
    709 	Fill in registers for the interrupt call
    710 	........................................................................*/
    711 	rmi.eax = 0x0000e300;
    712 	rmi.ds = segment;
    713 	rmi.esi = 0;
    714 	rmi.es = segment;
    715 	rmi.edi = sizeof(struct request_buffer);
    716 	/*........................................................................
    717 	call DPMI
    718 	........................................................................*/
    719 	int386x(DPMI_INT, &regs, &regs, &sregs);
    720 
    721 	/*------------------------------------------------------------------------
    722 	Fill in the caller's buffer with the user name
    723 	------------------------------------------------------------------------*/
    724 	strncpy(user_id, replybuf->object_name, 48);
    725 
    726 	/*------------------------------------------------------------------------
    727 	Free DOS memory
    728 	------------------------------------------------------------------------*/
    729 	memset (&regs, 0 ,sizeof(regs));
    730 	segread (&sregs);
    731 	regs.x.eax = DPMI_FREE_DOS_MEM;						// DPMI function to call
    732 	regs.x.edx = selector;									// ptr to free
    733 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    734 
    735 	return(0);
    736 
    737 }	/* end of IPX_Get_User_ID */
    738 #endif	//NOT_FOR_WIN95
    739 
    740 
    741 /***************************************************************************
    742  * IPX_Listen_For_Packet -- commands IPX to listen for a packet            *
    743  *                                                                         *
    744  * Before calling this function, you must fill in an ECB:						*
    745  *		SocketNumber:				must contain the socket you've opened,			*
    746  *										and are "listening" on								*
    747  *		Event_Service_Routine:	optionally points to a callback routine		*
    748  *		PacketCount:				set to 2, to tell IPX there are 2 areas to	*
    749  *										store the incoming data in							*
    750  *		Packet[0].Address:		set to the address of an IPXHeaderType			*
    751  *		Packet[0].Length:			sizeof(IPXHeaderType)								*
    752  *		Packet[1].Address:		address of data buffer, for the packet			*
    753  *		Packet[1].Length:			size of the data buffer								*
    754  *                                                                         *
    755  * When the packet is received, ECBType.CompletionCode will be 0 if 			*
    756  * successful.  Otherwise, some error occurred.										*
    757  *                                                                         *
    758  * You should initialize the ECB to 0's before filling it in.					*
    759  *                                                                         *
    760  * INPUT:                                                                  *
    761  *		ecb_ptr		pointer to a filled-in ECB; MUST be real-mode memory		*
    762  *                                                                         *
    763  * OUTPUT:                                                                 *
    764  *		0 = OK, IPX error otherwise														*
    765  *                                                                         *
    766  * WARNINGS:                                                               *
    767  *		The ECB must be located in real-mode memory, as well as the values	*
    768  *		pointed to in the ECB (the IPX Header, the buffer to send, etc.)		*
    769  *                                                                         *
    770  * HISTORY:                                                                *
    771  *   12/15/1994 BR : Created.                                              *
    772  *=========================================================================*/
    773 #ifdef NOT_FOR_WIN95
    774 int IPX_Listen_For_Packet(struct ECB *ecb_ptr)
    775 {
    776 	union REGS      regs;
    777 	struct SREGS    sregs;
    778 	RMIType rmi;
    779 
    780 	/*------------------------------------------------------------------------
    781 	Call IPX with ES:SI=ecb_ptr
    782 	------------------------------------------------------------------------*/
    783 	/*........................................................................
    784 	Fill in registers for the DPMI call
    785 	........................................................................*/
    786 	memset (&regs, 0 ,sizeof(regs));
    787 	segread (&sregs);
    788 	memset (&rmi, 0 ,sizeof(rmi));
    789 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    790 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    791 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    792 	regs.x.edi = FP_OFF(&rmi);
    793 	/*........................................................................
    794 	Fill in registers for the interrupt call
    795 	........................................................................*/
    796 	rmi.ebx = IPX_LISTEN_FOR_PACKET;
    797 	rmi.es = (short)((long)ecb_ptr >> 4);
    798 	rmi.esi = (long)((long)ecb_ptr & 0x000f);
    799 	/*........................................................................
    800 	call DPMI
    801 	........................................................................*/
    802 	int386x(DPMI_INT, &regs, &regs, &sregs);
    803 
    804 	return(rmi.eax & 0x00ff);
    805 
    806 }	/* end of IPX_Listen_For_Packet */
    807 #endif	//NOT_FOR_WIN95
    808 
    809 /***************************************************************************
    810  * IPX_Send_Packet -- commands IPX to send a packet                        *
    811  *                                                                         *
    812  * Before calling this function, you must fill in an ECB:						*
    813  *		SocketNumber:				must contain the socket you've opened,			*
    814  *										and are sending on									*
    815  *		Event_Service_Routine:	optionally points to a callback routine		*
    816  *		PacketCount:				set to 2, to tell IPX there are 2 areas the	*
    817  *										outgoing data is stored in							*
    818  *		Packet[0].Address:		set to the address of an IPXHeaderType			*
    819  *		Packet[0].Length:			sizeof(IPXHeaderType)								*
    820  *		Packet[1].Address:		address of buffer containing data to send		*
    821  *		Packet[1].Length:			size of the data buffer								*
    822  *		ImmediateAddress:			must be filled in with the node address of	*
    823  *										the bridge that will route the message;		*
    824  *										fill this in by calling IPX_Get_Local_Target	*
    825  *                                                                         *
    826  * Also, you must fill in the IPXHeaderType with certain values:				*
    827  *		PacketType:					set to 4 for IPX										*
    828  *		DestNetworkNumber:		Network Number of the destination system		*
    829  *		DestNetworkNode:			Node Address of the destination system			*
    830  *		DestNetworkSocket:		the destination system's socket to send to;	*
    831  *										this doesn't have to be the same as the		*
    832  *										socket opened on the local machine.				*
    833  *                                                                         *
    834  * You should initialize the ECB & IPXHeader to 0's before filling them in.*
    835  *                                                                         *
    836  * INPUT:                                                                  *
    837  *		ecb_ptr		pointer to a filled-in ECB											*
    838  *                                                                         *
    839  * OUTPUT:                                                                 *
    840  *		none.  This function doesn't return anything; the caller must check	*
    841  *    its ECB.CompletionCode for: 0 = OK, IPX Error otherwise.					*
    842  *                                                                         *
    843  * WARNINGS:                                                               *
    844  *		The ECB must be located in real-mode memory, as well as the values	*
    845  *		pointed to in the ECB (the IPX Header, the buffer to send, etc.)		*
    846  *                                                                         *
    847  * HISTORY:                                                                *
    848  *   12/15/1994 BR : Created.                                              *
    849  *=========================================================================*/
    850 #ifdef NOT_FOR_WIN95
    851 void IPX_Send_Packet(struct ECB *ecb_ptr)
    852 {
    853 	union REGS      regs;
    854 	struct SREGS    sregs;
    855 	RMIType rmi;
    856 
    857 	/*------------------------------------------------------------------------
    858 	Call IPX with ES:SI=ecb_ptr
    859 	------------------------------------------------------------------------*/
    860 	/*........................................................................
    861 	Fill in registers for the DPMI call
    862 	........................................................................*/
    863 	memset (&regs, 0 ,sizeof(regs));
    864 	segread (&sregs);
    865 	memset (&rmi, 0 ,sizeof(rmi));
    866 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    867 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    868 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    869 	regs.x.edi = FP_OFF(&rmi);
    870 	/*........................................................................
    871 	Fill in registers for the interrupt call
    872 	........................................................................*/
    873 	rmi.ebx = IPX_SEND_PACKET;
    874 	rmi.es = (short)((long)ecb_ptr >> 4);
    875 	rmi.esi = (long)((long)ecb_ptr & 0x000f);
    876 	/*........................................................................
    877 	call DPMI
    878 	........................................................................*/
    879 	int386x(DPMI_INT, &regs, &regs, &sregs);
    880 
    881 }	/* end of IPX_Send_Packet */
    882 #endif	//NOT_FOR_WIN95
    883 
    884 /***************************************************************************
    885  * IPX_Get_Local_Target -- fills in ImmediateAddress field of ECB          *
    886  *                                                                         *
    887  * Use this function to fill in the ECB's ImmediateAddress field when		*
    888  * sending a packet.  The Immediate Address is the node address of the		*
    889  * bridge that must route the message.  If there is no bridge, it's 			*
    890  * filled in with the destination Node Address.  In either case, it			*
    891  * will contain the proper value for sending.										*
    892  *                                                                         *
    893  * INPUT:                                                                  *
    894  *		dest_network			destination Network Number								*
    895  *		dest_node				destination Node Address								*
    896  *		dest_socket				destination Socket Number								*
    897  *		bridge_address			field to fill in with Immediate Address			*
    898  *                                                                         *
    899  * OUTPUT:                                                                 *
    900  *		0 = OK, error otherwise																*
    901  *                                                                         *
    902  * WARNINGS:                                                               *
    903  *		If the Connection Number is 0 (user not logged in), dest_network		*
    904  *		and dest_node will be garbage, and this routine will probably crash.	*
    905  *                                                                         *
    906  * HISTORY:                                                                *
    907  *   12/15/1994 BR : Created.                                              *
    908  *=========================================================================*/
    909 #ifdef NOT_FOR_WIN95
    910 int IPX_Get_Local_Target(unsigned char *dest_network, unsigned char *dest_node,
    911 	unsigned short dest_socket, unsigned char *bridge_address)
    912 {
    913 	struct request_buffer {
    914 		unsigned char   network_number [4];
    915 		unsigned char   physical_node  [6];
    916 		unsigned short  socket;
    917 	};
    918 	struct reply_buffer {
    919 		unsigned char   local_target [6];
    920 	};
    921 	unsigned int rc;
    922 	union REGS regs;
    923 	struct SREGS sregs;
    924 	RMIType rmi;
    925 	struct request_buffer *reqbuf;
    926 	struct reply_buffer *replybuf;
    927 	unsigned short segment;							// for DOS allocation
    928 	unsigned short selector;						// for DOS allocation
    929 
    930 	/*------------------------------------------------------------------------
    931 	Allocate DOS memory to store the buffers passed to the interrupt
    932 	------------------------------------------------------------------------*/
    933 	memset (&regs, 0 ,sizeof(regs));
    934 	segread (&sregs);
    935 	regs.x.eax = DPMI_ALLOC_DOS_MEM;						// DPMI function to call
    936 	regs.x.ebx = (sizeof(struct request_buffer) + 	// # paragraphs to allocate
    937 		sizeof(struct reply_buffer) + 15) >> 4;
    938 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    939 	/*........................................................................
    940 	If the carry flag is set, DPMI is indicating an error.
    941 	........................................................................*/
    942 	if (regs.x.cflag) {
    943 		return(-1);
    944 	}
    945 
    946 	/*........................................................................
    947 	Get pointers to allocated memory.
    948 	'reqbuf' is just the returned real-mode segment, multiplied by 16.
    949 	'replybuf' is an offset from 'reqbuf'.
    950 	........................................................................*/
    951 	segment = regs.w.ax;
    952 	selector = regs.w.dx;
    953 	reqbuf = (struct request_buffer *)(segment << 4);
    954 	replybuf = (struct reply_buffer *)
    955 		(((char *)reqbuf) + sizeof (struct request_buffer));
    956 
    957 	/*------------------------------------------------------------------------
    958 	Init the contents of the request & reply buffers
    959 	------------------------------------------------------------------------*/
    960 	memcpy(reqbuf->network_number, dest_network, 4);
    961 	memcpy(reqbuf->physical_node, dest_node, 6);
    962 	reqbuf->socket = dest_socket;
    963 
    964 	/*------------------------------------------------------------------------
    965 	Invoke IPX with DS:SI=&request_buffer, ES:DI=&reply_buffer
    966 	------------------------------------------------------------------------*/
    967 	/*........................................................................
    968 	Fill in registers for the DPMI call
    969 	........................................................................*/
    970 	memset (&regs, 0 ,sizeof(regs));
    971 	segread (&sregs);
    972 	memset (&rmi, 0 ,sizeof(rmi));
    973 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    974 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    975 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    976 	regs.x.edi = FP_OFF(&rmi);
    977 	/*........................................................................
    978 	Fill in registers for the interrupt call
    979 	........................................................................*/
    980 	rmi.ebx = IPX_GET_LOCAL_TARGET;
    981 	rmi.ds = segment;
    982 	rmi.esi = 0;
    983 	rmi.es = segment;
    984 	rmi.edi = sizeof(struct request_buffer);
    985 	/*........................................................................
    986 	call DPMI
    987 	........................................................................*/
    988 	int386x(DPMI_INT, &regs, &regs, &sregs);
    989 
    990 	rc = (rmi.eax & 0x00ff);
    991 	memcpy(bridge_address, replybuf->local_target, 6);
    992 
    993 	/*------------------------------------------------------------------------
    994 	Free DOS memory
    995 	------------------------------------------------------------------------*/
    996 	memset (&regs, 0 ,sizeof(regs));
    997 	segread (&sregs);
    998 	regs.x.eax = DPMI_FREE_DOS_MEM;						// DPMI function to call
    999 	regs.x.edx = selector;									// ptr to free
   1000 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
   1001 
   1002 	return(rc);
   1003 
   1004 }	/* end of IPX_Get_Local_Target */
   1005 
   1006 #endif	//NOT_FOR_WIN95
   1007 
   1008 /***************************************************************************
   1009  * IPX_Cancel_Event -- cancels an operation in progress                    *
   1010  *                                                                         *
   1011  * INPUT:                                                                  *
   1012  *		ecb_ptr		pointer to ECB event to cancel									*
   1013  *                                                                         *
   1014  * OUTPUT:                                                                 *
   1015  *		???																						*
   1016  *                                                                         *
   1017  * WARNINGS:                                                               *
   1018  *		The ECB must be located in real-mode memory, as well as the values	*
   1019  *		pointed to in the ECB (the IPX Header, the buffer to send, etc.)		*
   1020  *                                                                         *
   1021  * HISTORY:                                                                *
   1022  *   12/15/1994 BR : Created.                                              *
   1023  *=========================================================================*/
   1024 #ifdef NOT_FOR_WIN95
   1025 int IPX_Cancel_Event(struct ECB *ecb_ptr)
   1026 {
   1027 	union REGS      regs;
   1028 	struct SREGS    sregs;
   1029 	RMIType rmi;
   1030 	unsigned int rc;
   1031 
   1032 	/*........................................................................
   1033 	Fill in registers for the DPMI call
   1034 	........................................................................*/
   1035 	memset (&regs, 0 ,sizeof(regs));
   1036 	segread (&sregs);
   1037 	memset (&rmi, 0 ,sizeof(rmi));
   1038 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
   1039 	regs.w.bx = IPX_INT;					// interrupt # to invoke
   1040 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
   1041 	regs.x.edi = FP_OFF(&rmi);
   1042 	/*........................................................................
   1043 	Fill in registers for the interrupt call
   1044 	........................................................................*/
   1045 	rmi.ebx = IPX_CANCEL_EVENT;
   1046 	rmi.es = (short)((long)ecb_ptr >> 4);
   1047 	rmi.esi = (long)((long)ecb_ptr & 0x000f);
   1048 	/*........................................................................
   1049 	call DPMI
   1050 	........................................................................*/
   1051 	int386x(DPMI_INT, &regs, &regs, &sregs);
   1052 
   1053 	rc = (rmi.eax & 0x00ff);
   1054 
   1055 	return(rc);
   1056 
   1057 }	/* end of IPX_Cancel_Event */
   1058 #endif	//NOT_FOR_WIN95
   1059 
   1060 /***************************************************************************
   1061  * Let_IPX_Breath -- gives IPX some CPU time                               *
   1062  *                                                                         *
   1063  * Use this function if you're polling the ECB's InUse flag, waiting			*
   1064  * for it to go to 0:																		*
   1065  *                                                                         *
   1066  *		while ECBType.InUse																	*
   1067  *			Let_IPX_Breath();																	*
   1068  *                                                                         *
   1069  * INPUT:                                                                  *
   1070  *		none.																						*
   1071  *                                                                         *
   1072  * OUTPUT:                                                                 *
   1073  *		none.																						*
   1074  *                                                                         *
   1075  * WARNINGS:                                                               *
   1076  *		none.																						*
   1077  *                                                                         *
   1078  * HISTORY:                                                                *
   1079  *   12/15/1994 BR : Created.                                              *
   1080  *=========================================================================*/
   1081 #ifdef NOT_FOR_WIN95
   1082 void Let_IPX_Breath(void)
   1083 {
   1084 	union REGS      regs;
   1085 	struct SREGS    sregs;
   1086 	RMIType rmi;
   1087 
   1088 	/*........................................................................
   1089 	Fill in registers for the DPMI call
   1090 	........................................................................*/
   1091 	memset (&regs, 0 ,sizeof(regs));
   1092 	segread (&sregs);
   1093 	memset (&rmi, 0 ,sizeof(rmi));
   1094 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
   1095 	regs.w.bx = IPX_INT;					// interrupt # to invoke
   1096 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
   1097 	regs.x.edi = FP_OFF(&rmi);
   1098 	/*........................................................................
   1099 	Fill in registers for the interrupt call
   1100 	........................................................................*/
   1101 	rmi.ebx = IPX_RELINQUISH_CONTROL;
   1102 	/*........................................................................
   1103 	call DPMI
   1104 	........................................................................*/
   1105 	int386x(DPMI_INT, &regs, &regs, &sregs);
   1106 
   1107 }	/* end of Let_IPX_Breath */
   1108 #endif	//NOT_FOR_WIN95