1451 lines
26 KiB
NASM
1451 lines
26 KiB
NASM
![]() |
;
|
||
|
; Command & Conquer Red Alert(tm)
|
||
|
; Copyright 2025 Electronic Arts Inc.
|
||
|
;
|
||
|
; This program is free software: you can redistribute it and/or modify
|
||
|
; it under the terms of the GNU General Public License as published by
|
||
|
; the Free Software Foundation, either version 3 of the License, or
|
||
|
; (at your option) any later version.
|
||
|
;
|
||
|
; This program is distributed in the hope that it will be useful,
|
||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
; GNU General Public License for more details.
|
||
|
;
|
||
|
; You should have received a copy of the GNU General Public License
|
||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
;
|
||
|
|
||
|
|
||
|
|
||
|
.8086
|
||
|
|
||
|
|
||
|
.model large
|
||
|
option segment:USE16
|
||
|
option readonly
|
||
|
option oldstructs
|
||
|
|
||
|
|
||
|
assume ds:@data
|
||
|
assume es:nothing
|
||
|
|
||
|
|
||
|
RECEIVE_BUFFER_LENGTH =1024
|
||
|
MAX_RECEIVE_BUFFERS =32
|
||
|
|
||
|
|
||
|
externdef GLOBALDOSALLOC:far
|
||
|
externdef GLOBALDOSFREE:far
|
||
|
|
||
|
|
||
|
.data
|
||
|
|
||
|
IPXCallOffset dw 0
|
||
|
IPXCallSegment dw 0
|
||
|
RealSegment dw 0
|
||
|
PseudoES dw 0
|
||
|
|
||
|
|
||
|
|
||
|
RegisterDump db 32h dup (0)
|
||
|
|
||
|
MyNetworkNumber db 4 dup (?)
|
||
|
MyNodeAddress db 6 dup (?)
|
||
|
MySocket dw ?
|
||
|
|
||
|
ReceiveBufferSegment dw ?
|
||
|
ReceiveBufferSelector dw ?
|
||
|
ReceiveECBOffset dw ?
|
||
|
CurrentReceiveBuffer dw ?
|
||
|
LastPassedReceiveBuffer dw ?
|
||
|
RealModeCallbackSegment dw ?
|
||
|
RealModeCallbackOffset dw ?
|
||
|
|
||
|
CallbackRegisterDump db 32h dup (0)
|
||
|
|
||
|
Listening db ?
|
||
|
NoReenter db 0
|
||
|
IPXHold db 0
|
||
|
|
||
|
|
||
|
|
||
|
OFFS =0
|
||
|
SEGM =2
|
||
|
|
||
|
|
||
|
;---------------------------------------------------------------------------
|
||
|
;These defines are for the IPX functions. The function number is specified
|
||
|
;by placing it in BX when IPX is called. There are two ways to invoke IPX:
|
||
|
;use interrupt 0x7a, or use a function whose address is obtained by calling
|
||
|
;interrupt 0x2f with AX=0x7a00; the function address is returned in ES:DI.
|
||
|
;This is the preferred method, since other apps are known to use int 0x7a.
|
||
|
;---------------------------------------------------------------------------
|
||
|
IPX_OPEN_SOCKET = 0000h
|
||
|
IPX_CLOSE_SOCKET = 0001h
|
||
|
IPX_GET_LOCAL_TARGET = 0002h
|
||
|
IPX_SEND_PACKET = 0003h
|
||
|
IPX_LISTEN_FOR_PACKET = 0004h
|
||
|
IPX_SCHEDULE_EVENT = 0005h
|
||
|
IPX_CANCEL_EVENT = 0006h
|
||
|
IPX_GET_INTERVAL_MARKER = 0008h
|
||
|
IPX_GET_INTERNETWORK_ADDRESS = 0009h
|
||
|
IPX_RELINQUISH_CONTROL = 000Ah
|
||
|
IPX_DISCONNECT_FROM_TARGET = 000Bh
|
||
|
|
||
|
;/*---------------------------------------------------------------------------
|
||
|
;These defines are for various IPX error codes:
|
||
|
;---------------------------------------------------------------------------*/
|
||
|
IPXERR_CONNECTION_SEVERED = 00ech
|
||
|
IPXERR_CONNECTION_FAILED = 00edh
|
||
|
IPXERR_NO_CONNECTION = 00eeh
|
||
|
IPXERR_CONNECTION_TABLE_FULL = 00efh
|
||
|
IPXERR_NO_CANCEL_ECB = 00f9h
|
||
|
IPXERR_NO_PATH = 00fah
|
||
|
IPXERR_ECB_INACTIVE = 00fch
|
||
|
IPXERR_INVALID_PACKET_LENGTH = 00fdh
|
||
|
IPXERR_SOCKET_TABLE_FULL = 00feh
|
||
|
IPXERR_SOCKET_ERROR = 00ffh
|
||
|
|
||
|
;/*---------------------------------------------------------------------------
|
||
|
;These defines are for various interrupt vectors and DPMI functions:
|
||
|
;---------------------------------------------------------------------------*/
|
||
|
IPX_INT = 007ah
|
||
|
DPMI_INT = 0031h
|
||
|
DPMI_ALLOC_DOS_MEM = 0100h
|
||
|
DPMI_FREE_DOS_MEM = 0101h
|
||
|
DPMI_CALL_REAL_INT = 0300h
|
||
|
DPMI_CALL_REAL_PROC = 0301h
|
||
|
DPMI_ALLOCATE_CALLBACK = 0303h
|
||
|
DPMI_RELEASE_CALLBACK = 0304h
|
||
|
DPMI_LOCK_MEM = 0600h
|
||
|
DPMI_UNLOCK_MEM = 0601h
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
request_buffer struct
|
||
|
len word ?
|
||
|
buffer_type byte ?
|
||
|
connect_number byte ?
|
||
|
request_buffer ends
|
||
|
|
||
|
|
||
|
|
||
|
request_local_target_buffer struct
|
||
|
lt_network_number db ?,?,?,?
|
||
|
lt_physical_node db ?,?,?,?,?,?
|
||
|
lt_socket dw ?
|
||
|
request_local_target_buffer ends
|
||
|
|
||
|
|
||
|
local_target_reply_buffer struct
|
||
|
lt_local_target db ?,?,?,?,?,?
|
||
|
local_target_reply_buffer ends
|
||
|
|
||
|
|
||
|
|
||
|
reply_buffer struct
|
||
|
lem word ?
|
||
|
network_number byte ?,?,?,?
|
||
|
physical_node byte ?,?,?,?,?,?
|
||
|
server_socket word ?
|
||
|
reply_buffer ends
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
userid_buffer struct
|
||
|
struct_len word ?
|
||
|
object_id byte ?,?,?,?
|
||
|
object_type byte ?,?
|
||
|
object_name byte 48 dup(?)
|
||
|
login_time byte 7 dup (?)
|
||
|
reserved word ?
|
||
|
userid_buffer ends
|
||
|
|
||
|
.code
|
||
|
|
||
|
.386
|
||
|
|
||
|
include <pcmacro.16>
|
||
|
|
||
|
externdef pascal _IPX_Initiialise:far16
|
||
|
externdef pascal _IPX_Uninitialise:far16
|
||
|
|
||
|
|
||
|
_IPX_Initialise proc far pascal
|
||
|
|
||
|
push ebx
|
||
|
push ecx
|
||
|
push edx
|
||
|
push esi
|
||
|
push edi
|
||
|
push ebp
|
||
|
push ds
|
||
|
push es
|
||
|
push fs
|
||
|
push gs
|
||
|
|
||
|
mov ax,7a00h
|
||
|
int 2fh
|
||
|
and eax,0ffh
|
||
|
cmp al,-1
|
||
|
setz al
|
||
|
|
||
|
test al,al
|
||
|
jz @f
|
||
|
|
||
|
mov bx,@data
|
||
|
mov ds,bx
|
||
|
mov [IPXCallSegment],es
|
||
|
mov [IPXCallOffset],di
|
||
|
|
||
|
@@: pop gs
|
||
|
pop fs
|
||
|
pop es
|
||
|
pop ds
|
||
|
pop ebp
|
||
|
pop edi
|
||
|
pop esi
|
||
|
pop edx
|
||
|
pop ecx
|
||
|
pop ebx
|
||
|
ret
|
||
|
|
||
|
_IPX_Initialise endp
|
||
|
|
||
|
|
||
|
|
||
|
_IPX_Open_Socket95 proc far pascal uses bx cx dx si di ds es fs gs,
|
||
|
socket:word
|
||
|
|
||
|
mov bx,@data
|
||
|
mov ds,bx
|
||
|
mov bx,IPX_OPEN_SOCKET ;open socket
|
||
|
mov_w dx,[socket] ;socket number
|
||
|
mov_w [MySocket],dx ;save it for later
|
||
|
mov ax,0ffh ;long lived
|
||
|
|
||
|
call Call_IPX
|
||
|
|
||
|
ret
|
||
|
|
||
|
_IPX_Open_Socket95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
_IPX_Close_Socket95 proc far pascal uses ax bx cx dx si di ds es fs gs,
|
||
|
socket:word
|
||
|
|
||
|
mov bx,1
|
||
|
mov_w dx,[socket]
|
||
|
|
||
|
call Call_IPX
|
||
|
|
||
|
ret
|
||
|
|
||
|
_IPX_Close_Socket95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
_IPX_Uninitialise proc far pascal
|
||
|
|
||
|
;int 3
|
||
|
ret
|
||
|
|
||
|
_IPX_Uninitialise endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
_IPX_Get_Connection_Number95 proc far pascal uses bx cx dx si di ds es fs gs
|
||
|
|
||
|
mov ax,0dc00h
|
||
|
call Call_DOS
|
||
|
and eax,255
|
||
|
ret
|
||
|
|
||
|
_IPX_Get_Connection_Number95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
_IPX_Get_Internet_Address95 proc far pascal uses bx cx dx si di ds es fs gs,
|
||
|
connection_number :dword,
|
||
|
network_number_off :word,
|
||
|
network_number_seg :word,
|
||
|
physical_node_off :word,
|
||
|
physical_node_seg :word
|
||
|
|
||
|
local selector:word
|
||
|
local segmento:word
|
||
|
|
||
|
ret
|
||
|
ifdef cuts ;(unfinished)
|
||
|
;
|
||
|
; Allocate DOS memory for buffers passed to interrupt
|
||
|
;
|
||
|
int 3
|
||
|
xor ax,ax
|
||
|
mov bx,(sizeof reply_buffer + sizeof request_buffer + 15)
|
||
|
save bp
|
||
|
push ax
|
||
|
push bx
|
||
|
call GLOBALDOSALLOC
|
||
|
restore bp
|
||
|
test ax,ax
|
||
|
jz @@dpmi_error
|
||
|
|
||
|
mov [segmento],dx
|
||
|
mov [selector],ax
|
||
|
mov fs,dx
|
||
|
xor di,di
|
||
|
|
||
|
mov_w fs:[di.len],2
|
||
|
mov_b fs:[di.buffer_type],13h
|
||
|
mov_b al,[connection_number]
|
||
|
mov_b fs:[di.connect_number],al
|
||
|
|
||
|
mov di,sizeof request_buffer
|
||
|
mov fs:[di.len],12
|
||
|
|
||
|
|
||
|
mov ax,0e300h
|
||
|
mov ds,[segmento]
|
||
|
mov es,[segmento]
|
||
|
xor si,si
|
||
|
|
||
|
pusha
|
||
|
call Call_DOS
|
||
|
popa
|
||
|
|
||
|
les di,dword ptr [network_number_off]
|
||
|
mov ds,[selector]
|
||
|
mov si,sizeof request_buffer + network_number
|
||
|
movsd
|
||
|
|
||
|
les di,dword ptr [physical_node_off]
|
||
|
mov si,sizeof request_buffer + physical_node
|
||
|
movsd
|
||
|
movsw
|
||
|
|
||
|
;
|
||
|
; Save it here for posterity (or perhaps later use)
|
||
|
;
|
||
|
mov di,offset MyNetworkNumber
|
||
|
mov ax,@data
|
||
|
mov es,ax
|
||
|
mov ds,[selector]
|
||
|
mov si,sizeof request_buffer + network_number
|
||
|
movsd
|
||
|
|
||
|
mov di,offset MyNodeAddress
|
||
|
mov si,sizeof request_buffer + physical_node
|
||
|
movsd
|
||
|
movsw
|
||
|
|
||
|
|
||
|
;
|
||
|
; Free the DOS memory
|
||
|
;
|
||
|
mov bx,@data
|
||
|
mov ds,bx
|
||
|
mov es,bx
|
||
|
mov fs,bx
|
||
|
mov gs,bx
|
||
|
mov bx,[selector]
|
||
|
push bx
|
||
|
call GLOBALDOSFREE
|
||
|
|
||
|
xor ax,ax
|
||
|
ret
|
||
|
|
||
|
@@dpmi_error: mov ax,-1
|
||
|
ret
|
||
|
endif
|
||
|
|
||
|
_IPX_Get_Internet_Address95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
; Never called!!
|
||
|
|
||
|
_IPX_Get_User_ID95 proc far pascal uses bx cx dx si di ds es fs gs,
|
||
|
connection_number:dword,
|
||
|
user_id_off:word,
|
||
|
user_id_seg:word
|
||
|
|
||
|
local segmento:word
|
||
|
local selector:word
|
||
|
|
||
|
cmp [connection_number],0
|
||
|
jz @@return_error
|
||
|
|
||
|
;
|
||
|
; Allocate DOS memory for buffers passed to interrupt
|
||
|
;
|
||
|
xor ax,ax
|
||
|
mov bx,(sizeof reply_buffer + sizeof request_buffer + 15)
|
||
|
save bp
|
||
|
push ax
|
||
|
push bx
|
||
|
call GLOBALDOSALLOC
|
||
|
restore bp
|
||
|
test ax,ax
|
||
|
jz @@return_error
|
||
|
|
||
|
mov [segmento],dx
|
||
|
mov [selector],ax
|
||
|
mov fs,dx
|
||
|
xor di,di
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
|
||
|
mov_w fs:[di.len],2
|
||
|
mov_b fs:[di.buffer_type],16h
|
||
|
mov_b al,[connection_number]
|
||
|
mov_b fs:[di.connect_number],al
|
||
|
|
||
|
mov di,sizeof request_buffer
|
||
|
mov fs:[di.struct_len],sizeof userid_buffer-2
|
||
|
|
||
|
mov ax,0e300h
|
||
|
mov ds,[segmento]
|
||
|
mov es,[segmento]
|
||
|
xor si,si
|
||
|
|
||
|
pusha
|
||
|
call Call_DOS
|
||
|
popa
|
||
|
|
||
|
les di,dword ptr [user_id_off]
|
||
|
mov ds,[selector]
|
||
|
mov si,sizeof request_buffer + object_name
|
||
|
mov cx,48/4
|
||
|
rep movsd
|
||
|
|
||
|
;
|
||
|
; Free the DOS memory
|
||
|
;
|
||
|
mov bx,@data
|
||
|
mov ds,bx
|
||
|
mov es,bx
|
||
|
mov fs,bx
|
||
|
mov gs,bx
|
||
|
mov bx,[selector]
|
||
|
push bx
|
||
|
call GLOBALDOSFREE
|
||
|
|
||
|
xor ax,ax
|
||
|
ret
|
||
|
|
||
|
@@return_error: mov ax,-1
|
||
|
ret
|
||
|
|
||
|
_IPX_Get_User_ID95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
;---------------------------------------------------------------------------
|
||
|
;This is the IPX Packet structure. It's followed by the data itself, which
|
||
|
;can be up to 546 bytes long. Annotation of 'IPX' means IPX will set this
|
||
|
;field; annotation of 'APP' means the application must set the field.
|
||
|
;NOTE: All header fields are ordered high-byte,low-byte.
|
||
|
;---------------------------------------------------------------------------*/
|
||
|
IPXHeaderType struct
|
||
|
|
||
|
CheckSum dw ? ; IPX: Not used; always 0xffff
|
||
|
IPXLength dw ? ; IPX: Total size, incl header & data
|
||
|
TransportControl db ? ; IPX: # bridges message crossed
|
||
|
PacketType db ? ; APP: Set to 4 for IPX (5 for SPX)
|
||
|
DestNetworkNumber db ?,?,?,? ; APP: destination Network Number
|
||
|
DestNetworkNode db ?,?,?,?,?,? ; APP: destination Node Address
|
||
|
DestNetworkSocket dw ? ; APP: destination Socket Number
|
||
|
SourceNetworkNumber db ?,?,?,? ; IPX: source Network Number
|
||
|
SourceNetworkNode db ?,?,?,?,?,? ; IPX: source Node Address
|
||
|
SourceNetworkSocket dw ? ; IPX: source Socket Number
|
||
|
|
||
|
IPXHeaderType ends
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
;/*---------------------------------------------------------------------------
|
||
|
;This is the IPX Event Control Block. It serves as a communications area
|
||
|
;between IPX and the application for a single IPX operation. You should set
|
||
|
;up a separate ECB for each IPX operation you perform.
|
||
|
;---------------------------------------------------------------------------*/
|
||
|
|
||
|
ECB struct
|
||
|
|
||
|
Link_Address dd ?
|
||
|
Event_Service_Routine dd ? ; APP: event handler (NULL=none)
|
||
|
InUse db ? ; IPX: 0 = event complete
|
||
|
CompletionCode db ? ; IPX: event's return code
|
||
|
SocketNumber dw ? ; APP: socket to send data through
|
||
|
ConnectionID dw ? ; returned by Listen (???)
|
||
|
RestOfWorkspace dw ?
|
||
|
DriverWorkspace db 12 dup (?)
|
||
|
ImmediateAddress db 6 dup (?) ; returned by Get_Local_Target
|
||
|
PacketCount dw ?
|
||
|
PacketAddress0 dd ?
|
||
|
PacketLength0 dw ?
|
||
|
PacketAddress1 dd ?
|
||
|
PacketLength1 dw ?
|
||
|
|
||
|
ECB ends
|
||
|
|
||
|
|
||
|
SEND_ECB_OFFSET =0
|
||
|
SEND_HEADER_OFFSET =(sizeof ECB +3) AND 0fffch
|
||
|
SEND_BUFFER_OFFSET =(SEND_HEADER_OFFSET + sizeof IPXHeaderType +3) AND 0fffch
|
||
|
|
||
|
|
||
|
_IPX_Send_Packet95 proc far pascal uses ebx ecx edx esi edi ds es fs gs,
|
||
|
send_address :far ptr byte,
|
||
|
send_buffer :far ptr byte,
|
||
|
send_buffer_len :word
|
||
|
|
||
|
local selector :word
|
||
|
local segmento :word
|
||
|
local dos_send_ecb :far ptr ECB
|
||
|
local dos_send_header :far ptr IPXHeaderType
|
||
|
local dos_send_buffer :far ptr byte
|
||
|
local completion_code :word
|
||
|
|
||
|
;
|
||
|
; Allocate required DOS memory
|
||
|
;
|
||
|
xor ax,ax
|
||
|
mov bx,(sizeof ECB + sizeof IPXHeaderType + 1024 +31)
|
||
|
save bp
|
||
|
push ax
|
||
|
push bx
|
||
|
call GLOBALDOSALLOC
|
||
|
restore bp
|
||
|
test ax,ax
|
||
|
jz @@error
|
||
|
mov [segmento],dx
|
||
|
mov [selector],ax
|
||
|
|
||
|
;
|
||
|
; Set up the pointers to the dos memory
|
||
|
;
|
||
|
mov_w [dos_send_ecb+OFFS],SEND_ECB_OFFSET
|
||
|
mov_w [dos_send_ecb+SEGM],ax
|
||
|
mov_w [dos_send_header+OFFS],SEND_HEADER_OFFSET
|
||
|
mov_w [dos_send_header+SEGM],ax
|
||
|
mov_w [dos_send_buffer+OFFS],SEND_BUFFER_OFFSET
|
||
|
mov_w [dos_send_buffer+SEGM],ax
|
||
|
|
||
|
;
|
||
|
; Clear out the send ECB
|
||
|
;
|
||
|
xor al,al
|
||
|
mov cx,sizeof ECB
|
||
|
les di,[dos_send_ecb]
|
||
|
rep stosb
|
||
|
|
||
|
;
|
||
|
; Clear out the send header
|
||
|
;
|
||
|
mov cx,sizeof IPXHeaderType
|
||
|
les di,[dos_send_header]
|
||
|
rep stosb
|
||
|
|
||
|
;
|
||
|
; Copy the data to be sent into the send buffer
|
||
|
;
|
||
|
mov cx,546
|
||
|
cmp_w cx,[send_buffer_len]
|
||
|
jle @@got_buffer_len
|
||
|
mov_w cx,[send_buffer_len]
|
||
|
@@got_buffer_len:
|
||
|
; mov_w [send_buffer_len],546 ;always send same size packets (nice and big for Kali hehe)
|
||
|
les di,[dos_send_buffer]
|
||
|
lds si,[send_buffer]
|
||
|
rep movsb
|
||
|
|
||
|
;
|
||
|
; Fill in the ECB
|
||
|
;
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
mov fs,ax ;keep ptr to data seg in fs
|
||
|
les di,[dos_send_ecb]
|
||
|
|
||
|
mov ax,[MySocket]
|
||
|
mov es:[di.SocketNumber],ax
|
||
|
mov es:[di.PacketCount],2
|
||
|
mov ax,[selector]
|
||
|
shl eax,16
|
||
|
mov_w ax,[dos_send_header+OFFS]
|
||
|
mov_d es:[di.PacketAddress0],eax
|
||
|
mov_w es:[di.PacketLength0],sizeof IPXHeaderType
|
||
|
mov_w ax,[dos_send_buffer+OFFS]
|
||
|
mov_d es:[di.PacketAddress1],eax
|
||
|
mov_w ax,[send_buffer_len]
|
||
|
mov_w es:[di.PacketLength1],ax
|
||
|
|
||
|
;
|
||
|
; Fill in the address field
|
||
|
;
|
||
|
lds si,[send_address]
|
||
|
mov eax,[si]
|
||
|
mov_d es:[di.ImmediateAddress],eax
|
||
|
mov ax,[si+4]
|
||
|
mov_w es:[di.ImmediateAddress+4],ax
|
||
|
|
||
|
;
|
||
|
; Fill in the outgoing header
|
||
|
;
|
||
|
les di,[dos_send_header]
|
||
|
mov es:[di.PacketType],4
|
||
|
push fs:[MySocket]
|
||
|
pop es:[di.DestNetworkSocket]
|
||
|
|
||
|
;
|
||
|
; Fill in the nwtowrk number and node address
|
||
|
;
|
||
|
mov_d eax,fs:[MyNetworkNumber]
|
||
|
mov_d es:[di.DestNetworkNumber],eax
|
||
|
mov_d eax,fs:[MyNodeAddress]
|
||
|
mov_d es:[di.DestNetworkNode],eax
|
||
|
mov_w ax,fs:[MyNodeAddress+4]
|
||
|
mov_w es:[di.DestNetworkNode+4],ax
|
||
|
|
||
|
;
|
||
|
; Send that sucker!
|
||
|
;
|
||
|
mov es,[selector]
|
||
|
mov si,SEND_ECB_OFFSET
|
||
|
mov bx,IPX_SEND_PACKET
|
||
|
pusha
|
||
|
push fs
|
||
|
call Call_IPX
|
||
|
pop fs
|
||
|
popa
|
||
|
mov fs:[PseudoES],0
|
||
|
|
||
|
|
||
|
;
|
||
|
; Wait for the send to finish
|
||
|
;
|
||
|
@@wait_send_loop:
|
||
|
lds si,[dos_send_ecb]
|
||
|
cmp [si.InUse],0
|
||
|
jz @@done
|
||
|
|
||
|
mov bx,IPX_RELINQUISH_CONTROL
|
||
|
save bp
|
||
|
call Call_IPX
|
||
|
restore bp
|
||
|
jmp @@wait_send_loop
|
||
|
|
||
|
|
||
|
;
|
||
|
; Get the completion code
|
||
|
;
|
||
|
@@done: lds si,[dos_send_ecb]
|
||
|
mov al,[si.CompletionCode]
|
||
|
xor ah,ah
|
||
|
mov [completion_code],ax
|
||
|
|
||
|
;
|
||
|
; Free the DOS memory
|
||
|
;
|
||
|
mov bx,@data
|
||
|
mov ds,bx
|
||
|
mov es,bx
|
||
|
mov fs,bx
|
||
|
mov gs,bx
|
||
|
mov bx,[selector]
|
||
|
save bp
|
||
|
push bx
|
||
|
call GLOBALDOSFREE
|
||
|
restore bp
|
||
|
|
||
|
cmp [completion_code],0
|
||
|
jnz @@error
|
||
|
|
||
|
@@success: mov ax,1
|
||
|
ret
|
||
|
|
||
|
|
||
|
@@error: xor ax,ax
|
||
|
ret
|
||
|
|
||
|
|
||
|
_IPX_Send_Packet95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
_IPX_Broadcast_Packet95 proc far pascal uses ebx ecx edx esi edi ds es fs gs,
|
||
|
send_buffer :far ptr byte,
|
||
|
send_buffer_len :word
|
||
|
|
||
|
local selector :word
|
||
|
local segmento :word
|
||
|
local dos_send_ecb :far ptr ECB
|
||
|
local dos_send_header :far ptr IPXHeaderType
|
||
|
local dos_send_buffer :far ptr byte
|
||
|
local completion_code :word
|
||
|
|
||
|
;
|
||
|
; Allocate required DOS memory
|
||
|
;
|
||
|
xor ax,ax
|
||
|
mov bx,(sizeof ECB + sizeof IPXHeaderType + 1024 +31)
|
||
|
save bp
|
||
|
push ax
|
||
|
push bx
|
||
|
call GLOBALDOSALLOC
|
||
|
restore bp
|
||
|
test ax,ax
|
||
|
jz @@error
|
||
|
mov [segmento],dx
|
||
|
mov [selector],ax
|
||
|
|
||
|
;
|
||
|
; Set up the pointers to the dos memory
|
||
|
;
|
||
|
mov_w [dos_send_ecb+OFFS],SEND_ECB_OFFSET
|
||
|
mov_w [dos_send_ecb+SEGM],ax
|
||
|
mov_w [dos_send_header+OFFS],SEND_HEADER_OFFSET
|
||
|
mov_w [dos_send_header+SEGM],ax
|
||
|
mov_w [dos_send_buffer+OFFS],SEND_BUFFER_OFFSET
|
||
|
mov_w [dos_send_buffer+SEGM],ax
|
||
|
|
||
|
;
|
||
|
; Clear out the send ECB
|
||
|
;
|
||
|
xor al,al
|
||
|
mov cx,sizeof ECB
|
||
|
les di,[dos_send_ecb]
|
||
|
rep stosb
|
||
|
|
||
|
;
|
||
|
; Clear out the send header
|
||
|
;
|
||
|
mov cx,sizeof IPXHeaderType
|
||
|
les di,[dos_send_header]
|
||
|
rep stosb
|
||
|
|
||
|
;
|
||
|
; Copy the data to be sent into the send buffer
|
||
|
;
|
||
|
mov cx,546
|
||
|
cmp_w cx,[send_buffer_len]
|
||
|
jle @@got_buffer_len
|
||
|
mov_w cx,[send_buffer_len]
|
||
|
@@got_buffer_len:
|
||
|
; mov_w [send_buffer_len],546 ;always send same size packets (nice and big for Kali hehe)
|
||
|
les di,[dos_send_buffer]
|
||
|
lds si,[send_buffer]
|
||
|
rep movsb
|
||
|
|
||
|
;
|
||
|
; Fill in the ECB
|
||
|
;
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
mov fs,ax ;keep ptr to data seg in fs
|
||
|
les di,[dos_send_ecb]
|
||
|
|
||
|
mov ax,[MySocket]
|
||
|
mov es:[di.SocketNumber],ax
|
||
|
mov es:[di.PacketCount],2
|
||
|
mov ax,[selector]
|
||
|
shl eax,16
|
||
|
mov_w ax,[dos_send_header+OFFS]
|
||
|
mov_d es:[di.PacketAddress0],eax
|
||
|
mov_w es:[di.PacketLength0],sizeof IPXHeaderType
|
||
|
mov_w ax,[dos_send_buffer+OFFS]
|
||
|
mov_d es:[di.PacketAddress1],eax
|
||
|
mov_w ax,[send_buffer_len]
|
||
|
mov_w es:[di.PacketLength1],ax
|
||
|
|
||
|
;
|
||
|
; Fill in the address field
|
||
|
;
|
||
|
mov_d es:[di.ImmediateAddress],0ffffffffh
|
||
|
mov_w es:[di.ImmediateAddress+4],0ffffh
|
||
|
|
||
|
;
|
||
|
; Fill in the outgoing header
|
||
|
;
|
||
|
les di,[dos_send_header]
|
||
|
mov es:[di.PacketType],4
|
||
|
push fs:[MySocket]
|
||
|
pop es:[di.DestNetworkSocket]
|
||
|
|
||
|
;
|
||
|
; Fill in the nwtowrk number and node address
|
||
|
;
|
||
|
mov_d es:[di.DestNetworkNumber],0ffffffffh
|
||
|
mov_d es:[di.DestNetworkNode],0ffffffffh
|
||
|
mov_w es:[di.DestNetworkNode+4],0ffffh
|
||
|
|
||
|
;
|
||
|
; Send that sucker!
|
||
|
;
|
||
|
mov es,[selector]
|
||
|
mov si,SEND_ECB_OFFSET
|
||
|
mov bx,IPX_SEND_PACKET
|
||
|
pusha
|
||
|
push fs
|
||
|
call Call_IPX
|
||
|
pop fs
|
||
|
popa
|
||
|
mov fs:[PseudoES],0
|
||
|
|
||
|
;
|
||
|
; Wait for the send to finish
|
||
|
;
|
||
|
@@wait_send_loop:
|
||
|
lds si,[dos_send_ecb]
|
||
|
cmp [si.InUse],0
|
||
|
jz @@done
|
||
|
|
||
|
mov bx,IPX_RELINQUISH_CONTROL
|
||
|
save bp
|
||
|
call Call_IPX
|
||
|
restore bp
|
||
|
jmp @@wait_send_loop
|
||
|
|
||
|
|
||
|
|
||
|
;
|
||
|
; Get the completion code
|
||
|
;
|
||
|
@@done: lds si,[dos_send_ecb]
|
||
|
mov al,[si.CompletionCode]
|
||
|
xor ah,ah
|
||
|
mov [completion_code],ax
|
||
|
|
||
|
;
|
||
|
; Free the DOS memory
|
||
|
;
|
||
|
mov bx,@data
|
||
|
mov ds,bx
|
||
|
mov es,bx
|
||
|
mov fs,bx
|
||
|
mov gs,bx
|
||
|
mov bx,[selector]
|
||
|
save bp
|
||
|
push bx
|
||
|
call GLOBALDOSFREE
|
||
|
restore bp
|
||
|
|
||
|
cmp [completion_code],0
|
||
|
jnz @@error
|
||
|
|
||
|
|
||
|
@@success: mov ax,1
|
||
|
ret
|
||
|
|
||
|
|
||
|
@@error: xor ax,ax
|
||
|
ret
|
||
|
|
||
|
|
||
|
_IPX_Broadcast_Packet95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
_IPX_Get_Local_Target95 proc far pascal uses ebx ecx edx esi edi ds es fs gs,
|
||
|
dest_network :far ptr byte,
|
||
|
dest_node :far ptr byte,
|
||
|
socket :word,
|
||
|
bridge_address :far ptr byte
|
||
|
|
||
|
|
||
|
local segmento :word
|
||
|
local selector :word
|
||
|
local result_code :word
|
||
|
|
||
|
;
|
||
|
; Allocate DOS memory for buffers passed to interrupt
|
||
|
;
|
||
|
xor ax,ax
|
||
|
mov bx,(sizeof local_target_reply_buffer + \
|
||
|
sizeof request_local_target_buffer + 15)
|
||
|
save bp
|
||
|
push ax
|
||
|
push bx
|
||
|
call GLOBALDOSALLOC
|
||
|
restore bp
|
||
|
test ax,ax
|
||
|
jz @@return_error
|
||
|
|
||
|
mov [segmento],dx
|
||
|
mov [selector],ax
|
||
|
mov fs,ax
|
||
|
xor di,di
|
||
|
|
||
|
;
|
||
|
; Init the request structure
|
||
|
;
|
||
|
lds si,[dest_network]
|
||
|
mov_d eax,[si]
|
||
|
mov_d fs:[di.lt_network_number],eax
|
||
|
lds si,[dest_node]
|
||
|
mov eax,[si]
|
||
|
mov_d fs:[di.lt_physical_node],eax
|
||
|
mov_w ax,[si+4]
|
||
|
mov_w fs:[di.lt_physical_node+4],ax
|
||
|
mov ax,[socket]
|
||
|
mov fs:[di.lt_socket],ax
|
||
|
|
||
|
mov bx,IPX_GET_LOCAL_TARGET
|
||
|
mov ax,[selector]
|
||
|
mov ds,ax
|
||
|
xor si,si
|
||
|
mov es,ax
|
||
|
mov di,sizeof request_local_target_buffer
|
||
|
|
||
|
push bp
|
||
|
call Call_IPX
|
||
|
pop bp
|
||
|
|
||
|
mov [result_code],ax
|
||
|
|
||
|
mov ds,[selector]
|
||
|
mov si,sizeof request_local_target_buffer + lt_local_target
|
||
|
les di,[bridge_address]
|
||
|
movsd
|
||
|
movsw
|
||
|
|
||
|
;
|
||
|
; Free the DOS memory
|
||
|
;
|
||
|
mov bx,@data
|
||
|
mov ds,bx
|
||
|
mov es,bx
|
||
|
mov fs,bx
|
||
|
mov gs,bx
|
||
|
mov bx,[selector]
|
||
|
save bp
|
||
|
push bx
|
||
|
call GLOBALDOSFREE
|
||
|
restore bp
|
||
|
|
||
|
;
|
||
|
; Return the IPX result code
|
||
|
;
|
||
|
mov ax,[result_code]
|
||
|
ret
|
||
|
|
||
|
@@return_error: mov ax,-1
|
||
|
ret
|
||
|
|
||
|
_IPX_Get_Local_Target95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
_IPX_Get_Outstanding_Buffer95 proc far pascal uses ebx ecx edx esi edi ebp ds es fs gs,
|
||
|
copy_receive_buffer:far ptr byte
|
||
|
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
|
||
|
xor ax,ax
|
||
|
mov si,[LastPassedReceiveBuffer]
|
||
|
cmp si,[CurrentReceiveBuffer]
|
||
|
jz @@done
|
||
|
|
||
|
push ds
|
||
|
mov cx,RECEIVE_BUFFER_LENGTH/4
|
||
|
mov ds,[ReceiveBufferSelector]
|
||
|
les di,[copy_receive_buffer]
|
||
|
rep movsd
|
||
|
pop ds
|
||
|
|
||
|
cmp si,RECEIVE_BUFFER_LENGTH*MAX_RECEIVE_BUFFERS
|
||
|
jc @@no_wrap
|
||
|
xor si,si
|
||
|
@@no_wrap: mov [LastPassedReceiveBuffer],si
|
||
|
|
||
|
mov ax,1
|
||
|
|
||
|
@@done: ret
|
||
|
|
||
|
_IPX_Get_Outstanding_Buffer95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Receive_Callback proc far
|
||
|
|
||
|
pushf
|
||
|
cli
|
||
|
cld
|
||
|
pushad
|
||
|
push ds
|
||
|
push es
|
||
|
push fs
|
||
|
push gs
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
cmp [NoReenter],0
|
||
|
jnz @@out
|
||
|
mov [NoReenter],1
|
||
|
mov ax,[CurrentReceiveBuffer]
|
||
|
|
||
|
add ax,RECEIVE_BUFFER_LENGTH
|
||
|
cmp ax,RECEIVE_BUFFER_LENGTH*MAX_RECEIVE_BUFFERS
|
||
|
jc @@no_wrap
|
||
|
xor ax,ax
|
||
|
@@no_wrap: mov [CurrentReceiveBuffer],ax
|
||
|
|
||
|
call Listen_For_Packet
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
mov [NoReenter],0
|
||
|
|
||
|
@@out: pop gs
|
||
|
pop fs
|
||
|
pop es
|
||
|
pop ds
|
||
|
popad
|
||
|
popf
|
||
|
ret
|
||
|
|
||
|
Receive_Callback endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Init_Receive_ECB proc near uses eax ebx ecx edx esi edi ebp ds es
|
||
|
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
mov es,[ReceiveBufferSelector]
|
||
|
|
||
|
;
|
||
|
; Clear out the ECB
|
||
|
;
|
||
|
mov di,[ReceiveECBOffset]
|
||
|
mov cx,sizeof ECB
|
||
|
xor al,al
|
||
|
rep stosb
|
||
|
|
||
|
|
||
|
;
|
||
|
; Set up the ECB
|
||
|
;
|
||
|
;
|
||
|
;General ECB data
|
||
|
mov di,[ReceiveECBOffset]
|
||
|
mov ax,[MySocket]
|
||
|
mov es:[di.SocketNumber],ax
|
||
|
mov es:[di.PacketCount],2
|
||
|
|
||
|
;
|
||
|
; Packet address for IPX header
|
||
|
mov ax,[CurrentReceiveBuffer]
|
||
|
mov bx,[ReceiveBufferSelector]
|
||
|
mov_w es:[di.PacketAddress0+OFFS],ax
|
||
|
mov_w es:[di.PacketAddress0+SEGM],bx
|
||
|
mov es:[di.PacketLength0],sizeof IPXHeaderType
|
||
|
|
||
|
;
|
||
|
; Packet address for receive buffer
|
||
|
mov ax,[CurrentReceiveBuffer]
|
||
|
add ax,sizeof IPXHeaderType
|
||
|
mov_w es:[di.PacketAddress1+OFFS],ax
|
||
|
mov_w es:[di.PacketAddress1+SEGM],bx
|
||
|
mov es:[di.PacketLength1],546
|
||
|
|
||
|
;
|
||
|
; Set up the callback address
|
||
|
mov ax,[RealModeCallbackOffset]
|
||
|
mov_w es:[di.Event_Service_Routine+OFFS],offset Receive_Callback ;ax
|
||
|
mov ax,[RealModeCallbackSegment]
|
||
|
mov_w es:[di.Event_Service_Routine+SEGM],cs ;ax
|
||
|
|
||
|
ret
|
||
|
|
||
|
Init_Receive_ECB endp
|
||
|
|
||
|
|
||
|
_IPX_Start_Listening95 proc far pascal uses ebx ecx edx esi edi ebp ds es fs gs
|
||
|
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
cmp [Listening],0
|
||
|
jnz @@restart ;already listening
|
||
|
|
||
|
;
|
||
|
; Allocate and lock DOS memory for listen
|
||
|
; ECB and receive buffers
|
||
|
;
|
||
|
mov bx,(RECEIVE_BUFFER_LENGTH*MAX_RECEIVE_BUFFERS + sizeof ECB + 15)
|
||
|
xor ax,ax
|
||
|
save bp,ds
|
||
|
push ax
|
||
|
push bx
|
||
|
call GLOBALDOSALLOC
|
||
|
restore bp,ds
|
||
|
test ax,ax
|
||
|
jz @@error
|
||
|
|
||
|
mov [ReceiveBufferSegment],dx
|
||
|
mov [ReceiveBufferSelector],ax
|
||
|
|
||
|
;
|
||
|
; Set up pointers to the DOS memory
|
||
|
;
|
||
|
mov [ReceiveECBOffset],RECEIVE_BUFFER_LENGTH * MAX_RECEIVE_BUFFERS
|
||
|
mov [CurrentReceiveBuffer],0 ;1st receive buffer
|
||
|
mov [LastPassedReceiveBuffer],0
|
||
|
|
||
|
;
|
||
|
; Set up a real mode callback function
|
||
|
;
|
||
|
;mov ax,DPMI_ALLOCATE_CALLBACK
|
||
|
;mov si,offset Receive_Callback
|
||
|
;mov di,offset CallbackRegisterDump
|
||
|
;push cs
|
||
|
;pop ds
|
||
|
;mov bx,@data
|
||
|
;mov es,bx
|
||
|
;save bp
|
||
|
;int 31h
|
||
|
;restore bp
|
||
|
;bcs @@error
|
||
|
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
mov [RealModeCallbackSegment],cx
|
||
|
mov [RealModeCallbackOffset],dx
|
||
|
|
||
|
@@restart: save ds
|
||
|
call Listen_For_Packet
|
||
|
restore ds
|
||
|
mov [Listening],1
|
||
|
|
||
|
@@out: mov ax,1
|
||
|
ret
|
||
|
|
||
|
@@error: xor ax,ax
|
||
|
ret
|
||
|
|
||
|
_IPX_Start_Listening95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
_IPX_Shut_Down95 proc far pascal uses eax ebx ecx edx esi edi ebp ds es fs gs
|
||
|
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
cmp [Listening],0
|
||
|
jz @@out
|
||
|
|
||
|
;
|
||
|
; Stop listening for a packet
|
||
|
;
|
||
|
mov es,[ReceiveBufferSelector]
|
||
|
mov si,[ReceiveECBOffset]
|
||
|
mov bx,IPX_CANCEL_EVENT
|
||
|
save bp,ds
|
||
|
call Call_IPX
|
||
|
restore bp,ds
|
||
|
|
||
|
;
|
||
|
; Remove the real mode callback function
|
||
|
;
|
||
|
;mov cx,[RealModeCallbackSegment]
|
||
|
;mov dx,[RealModeCallbackOffset]
|
||
|
;mov ax,DPMI_RELEASE_CALLBACK
|
||
|
;save bp,ds
|
||
|
;int 31h
|
||
|
;restore bp,ds
|
||
|
|
||
|
;
|
||
|
; Free the DOS memory
|
||
|
;
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
mov es,ax
|
||
|
mov ax,[ReceiveBufferSelector]
|
||
|
save bp,ds
|
||
|
push ax
|
||
|
call GLOBALDOSFREE
|
||
|
restore bp,ds
|
||
|
|
||
|
mov [Listening],0
|
||
|
|
||
|
@@out: ret
|
||
|
|
||
|
_IPX_Shut_Down95 endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Listen_For_Packet proc near uses ebx ecx edx esi edi ebp ds es fs gs
|
||
|
|
||
|
call Init_Receive_ECB
|
||
|
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
mov es,[ReceiveBufferSelector]
|
||
|
mov si,[ReceiveECBOffset]
|
||
|
mov bx,IPX_LISTEN_FOR_PACKET
|
||
|
save ds
|
||
|
call Call_IPX
|
||
|
restore ds
|
||
|
mov [PseudoES],0
|
||
|
|
||
|
ret
|
||
|
|
||
|
Listen_For_Packet endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Call_IPX proc far
|
||
|
|
||
|
push gs
|
||
|
push ax
|
||
|
mov ax,@data
|
||
|
mov gs,ax
|
||
|
pop ax
|
||
|
|
||
|
push bp
|
||
|
mov bp,offset IPXCallOffset
|
||
|
call dword ptr gs:[bp]
|
||
|
pop bp
|
||
|
|
||
|
pop gs
|
||
|
ret
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
push gs
|
||
|
push ax
|
||
|
mov ax,@data
|
||
|
mov gs,ax
|
||
|
pop ax
|
||
|
|
||
|
;
|
||
|
; Prevent reenterancy
|
||
|
;
|
||
|
@@hold: ;cmp gs:[IPXHold],0
|
||
|
;jnz @@hold
|
||
|
|
||
|
mov gs:[IPXHold],1
|
||
|
|
||
|
;
|
||
|
; Dump the registers first so we can use them
|
||
|
;
|
||
|
mov_d gs:[RegisterDump+0ch],0
|
||
|
mov_d gs:[RegisterDump],edi
|
||
|
mov_d gs:[RegisterDump+4],esi
|
||
|
mov_d gs:[RegisterDump+8],ebp
|
||
|
mov_d gs:[RegisterDump+10h],ebx
|
||
|
mov_d gs:[RegisterDump+14h],edx
|
||
|
mov_d gs:[RegisterDump+18h],ecx
|
||
|
mov_d gs:[RegisterDump+1ch],eax
|
||
|
|
||
|
push gs
|
||
|
xor ax,ax
|
||
|
push ax
|
||
|
mov ax,4096 ;4k real mode stack
|
||
|
push ax
|
||
|
call GLOBALDOSALLOC
|
||
|
pop gs
|
||
|
mov bx,4094 ;stack ptr
|
||
|
test ax,ax
|
||
|
jnz @f
|
||
|
xor bx,bx
|
||
|
|
||
|
;
|
||
|
; Set up stack addr to zero - DPMI will supply a real mode stack
|
||
|
;
|
||
|
@@: mov_w gs:[RegisterDump+2eh],bx ;sp
|
||
|
mov_w gs:[RegisterDump+30h],dx ;ss
|
||
|
save ax ;save selector so we can free the memory later
|
||
|
|
||
|
|
||
|
;
|
||
|
; Dump the flags
|
||
|
;
|
||
|
pushf
|
||
|
pop gs:[word ptr RegisterDump+20h]
|
||
|
|
||
|
;
|
||
|
; Set up all segment register areas to point to our real mode segment
|
||
|
;
|
||
|
mov_w gs:[RegisterDump+22h],es
|
||
|
mov_w gs:[RegisterDump+24h],ds
|
||
|
mov_w gs:[RegisterDump+26h],fs
|
||
|
mov_w gs:[RegisterDump+28h],gs
|
||
|
|
||
|
cmp gs:[PseudoES],0
|
||
|
jz @f
|
||
|
mov ax,gs:[PseudoES]
|
||
|
mov_w gs:[RegisterDump+22h],ax
|
||
|
@@:
|
||
|
|
||
|
|
||
|
;
|
||
|
; Set up the address to call
|
||
|
;
|
||
|
mov ax,gs:[IPXCallSegment]
|
||
|
mov_w gs:[RegisterDump+2ch],ax
|
||
|
mov ax,gs:[IPXCallOffset]
|
||
|
mov_w gs:[RegisterDump+2ah],ax
|
||
|
|
||
|
mov ax,DPMI_CALL_REAL_INT ; Call real mode procedure with far return frame
|
||
|
xor bh,bh ; flags - should be zero
|
||
|
mov bl,07ah ; IPX interrupt
|
||
|
mov ecx,0 ;512 ; number of words to copy from the protected mode stack
|
||
|
mov di,offset RegisterDump
|
||
|
push gs
|
||
|
pop es
|
||
|
save gs
|
||
|
;push ss
|
||
|
;push sp
|
||
|
int 31h ;DPMI interrupt
|
||
|
|
||
|
;pop ax
|
||
|
;pop bx
|
||
|
;pushf
|
||
|
;pop cx
|
||
|
;cli
|
||
|
;mov sp,ax
|
||
|
;mov ss,bx
|
||
|
;add sp,2
|
||
|
;push cx
|
||
|
;popf
|
||
|
|
||
|
restore gs
|
||
|
|
||
|
mov ax,@data
|
||
|
mov ds,ax
|
||
|
mov es,ax
|
||
|
mov fs,ax
|
||
|
mov gs,ax
|
||
|
call GLOBALDOSFREE
|
||
|
|
||
|
|
||
|
mov_d eax,gs:[RegisterDump+1ch]
|
||
|
mov gs:[IPXHold],0
|
||
|
pop gs
|
||
|
|
||
|
ret
|
||
|
|
||
|
|
||
|
Call_IPX endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Call_DOS proc far
|
||
|
|
||
|
push gs
|
||
|
push ax
|
||
|
mov ax,@data
|
||
|
mov gs,ax
|
||
|
pop ax
|
||
|
;
|
||
|
; Dump the registers first so we can use them
|
||
|
;
|
||
|
mov_d gs:[RegisterDump],edi
|
||
|
mov_d gs:[RegisterDump+4],esi
|
||
|
mov_d gs:[RegisterDump+8],ebp
|
||
|
mov_d gs:[RegisterDump+10h],ebx
|
||
|
mov_d gs:[RegisterDump+14h],edx
|
||
|
mov_d gs:[RegisterDump+18h],ecx
|
||
|
mov_d gs:[RegisterDump+1ch],eax
|
||
|
|
||
|
;
|
||
|
; Dump the flags
|
||
|
;
|
||
|
pushf
|
||
|
pop gs:[word ptr RegisterDump+20h]
|
||
|
|
||
|
;
|
||
|
; Set up all segment register areas to point to our real mode segment
|
||
|
;
|
||
|
mov_w gs:[RegisterDump+22h],es
|
||
|
mov_w gs:[RegisterDump+24h],ds
|
||
|
mov_w gs:[RegisterDump+26h],fs
|
||
|
mov_w gs:[RegisterDump+28h],gs
|
||
|
|
||
|
;
|
||
|
; Set up stack addr to zero - DPMI will supply a real mode stack
|
||
|
;
|
||
|
xor ax,ax
|
||
|
mov_w gs:[RegisterDump+2eh],ax ;sp
|
||
|
mov_w gs:[RegisterDump+30h],ax ;ss
|
||
|
|
||
|
mov ax,DPMI_CALL_REAL_INT; Simulate real mode interrupt
|
||
|
xor bh,bh ; flags - should be zero
|
||
|
mov bl,21h ; interrupt number
|
||
|
mov ecx,0 ;512 ; number of words to copy from the protected mode stack
|
||
|
mov di,offset RegisterDump
|
||
|
push gs
|
||
|
pop es
|
||
|
save gs
|
||
|
int 31h ;DPMI interrupt
|
||
|
restore gs
|
||
|
|
||
|
mov_d edi,gs:[RegisterDump]
|
||
|
mov_d esi,gs:[RegisterDump+4]
|
||
|
mov_d ebp,gs:[RegisterDump+8]
|
||
|
mov_d ebx,gs:[RegisterDump+10h]
|
||
|
mov_d edx,gs:[RegisterDump+14h]
|
||
|
mov_d ecx,gs:[RegisterDump+18h]
|
||
|
mov_d eax,gs:[RegisterDump+1ch]
|
||
|
mov_w es,gs:[RegisterDump+22h]
|
||
|
mov_w ds,gs:[RegisterDump+24h]
|
||
|
pop gs
|
||
|
|
||
|
ret
|
||
|
|
||
|
|
||
|
Call_DOS endp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|