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