| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450 |
- ;
- ; 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
|