IPXREAL.ASM (13381B)
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 ;*************************************************************************** 17 ;** 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 ** 18 ;*************************************************************************** 19 ;* * 20 ;* Project Name : VQLIB * 21 ;* * 22 ;* File Name : HANDLER.ASM * 23 ;* * 24 ;* Programmer : Bill Randolph * 25 ;* * 26 ;* Start Date : April 7, 1995 * 27 ;* * 28 ;* Last Update : April 7, 1995 [BRR] * 29 ;* * 30 ;*-------------------------------------------------------------------------* 31 ;* Functions: * 32 ;* IPXHandler -- callback routine for IPX * 33 ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 34 ;********************* Model & Processor Directives ************************ 35 IDEAL 36 MODEL LARGE 37 P386N 38 LOCALS ?? 39 40 41 ;******************************** Includes ********************************* 42 43 44 ;******************************** Defines *********************************** 45 46 47 ;****************************** Declarations ******************************** 48 global C IPXHandler:FAR 49 50 51 ;********************************* Code ************************************ 52 CODESEG 53 54 55 ;--------------------------------------------------------------------------- 56 ; The markers let the application verify that it's mapping this memory 57 ; correctly. 58 ;--------------------------------------------------------------------------- 59 Marker1 DW 1111h ; placeholder to find data start 60 61 ;--------------------------------------------------------------------------- 62 ; This is the IPX Event Control Block: 63 ;--------------------------------------------------------------------------- 64 ECB_LinkAddress DD ? 65 ECB_EventServiceRoutine DD ? ; Event Handler ptr 66 ECB_InUse DB ? ; 0 = event is complete 67 ECB_CompletionCode DB ? ; 0 = OK, IPX error otherwise 68 ECB_SocketNumber DW ? ; socket to listen/send on 69 ECB_ConnectionID DW ? 70 ECB_RestOfWorkspace DW ? 71 ECB_DriverWorkSpace DB 12 DUP (?) 72 ECB_ImmediateAddress DB 6 DUP (?) ; bridge address 73 ECB_PacketCount DW ? ; # data areas (2) 74 ECB_HeaderAddress DD ? ; ptr to IPX header buffer 75 ECB_HeaderLength DW ? ; length of IPX header buffer 76 ECB_PacketAddress DD ? ; ptr to packet buffer 77 ECB_PacketLength DW ? ; length of packet buffer 78 79 ;--------------------------------------------------------------------------- 80 ; The rest of the variables are for telling IPX which buffer to store the 81 ; next incoming packet in. They must be initialized by the application. 82 ;--------------------------------------------------------------------------- 83 NumBufs DW 0 ; # buffers provided by app 84 BufferFlags DD 0 ; array of in-use flags (1 = in use) 85 PacketSize DW 0 ; total size of 1 buf (incl IPX hdr) 86 FirstPacketBuf DD 0 ; ptr to 1st packet buffer 87 CurIndex DW 0 ; current packet/flag index 88 CurPacketBuf DD 0 ; ptr to current packet buf 89 FuncOffset DW StartLabel ; offset of our routine 90 91 ;--------------------------------------------------------------------------- 92 ; These values are for preventing re-entrancy; they're currently not used. 93 ;--------------------------------------------------------------------------- 94 Semaphore DB 0 ; prevents re-entrancy 95 ReEntrantCount DW 0 ; times we've been called re-entrantly 96 97 ;--------------------------------------------------------------------------- 98 ; Local stack space 99 ;--------------------------------------------------------------------------- 100 StackPtr DW 0 ; saved copy of stack ptr 101 StackSeg DW 0 ; saved copy of stack seg 102 StackPtr_int DW 0 ; our internal stack ptr 103 StackSeg_int DW 0 ; our internal stack seg 104 StackCheck DW 1234h ; check for stack overflow 105 DW 256 DUP (0) ; stack storage space 106 StackSpace DW 0 ; label for our stack space 107 108 ;--------------------------------------------------------------------------- 109 ; These bytes mark the end of the real-mode data area 110 ;--------------------------------------------------------------------------- 111 Marker2 DW 2222h ; placeholder to find data end 112 113 114 ;*************************************************************************** 115 ;* IPXHandler -- IPX callback routine * 116 ;* * 117 ;* This routine is assembled as a stand-alone executable, then loaded * 118 ;* into low DOS memory by a protected-mode application. * 119 ;* * 120 ;* INPUT: * 121 ;* none. * 122 ;* * 123 ;* OUTPUT: * 124 ;* none. * 125 ;* * 126 ;* WARNINGS: * 127 ;* none. * 128 ;* * 129 ;* HISTORY: * 130 ;* 04/07/1995 BRR : Created. * 131 ;*=========================================================================* 132 label StartLabel 133 PROC IPXHandler C FAR USES 134 135 ;................................................................... 136 ; Turn off interrupts; make sure memory copies go forward 137 ;................................................................... 138 pushf 139 cli 140 cld 141 142 ;................................................................... 143 ; Set up segment registers to point DS to CS 144 ;................................................................... 145 push ds 146 push ax 147 mov ax,cs 148 mov ds,ax 149 150 ;................................................................... 151 ; Set up our local stack; save SS & SP first. 152 ;................................................................... 153 mov [StackSeg],ss 154 mov [StackPtr],sp 155 mov [StackPtr_int], OFFSET StackSpace 156 mov [StackSeg_int], SEG StackSpace 157 lss sp, [DWORD PTR StackPtr_int] 158 159 160 ;................................................................... 161 ; Save all registers 162 ;................................................................... 163 pushad 164 push es 165 166 ;................................................................... 167 ; If we've been called re-entrantly, just exit 168 ;................................................................... 169 cmp [Semaphore],0 170 jz ??Start_Handler 171 add [ReEntrantCount],1 172 jmp ??Exit_Handler 173 174 ??Start_Handler: 175 ;................................................................... 176 ; Set our semaphore 177 ;................................................................... 178 mov [Semaphore],1 179 180 ;------------------------------------------------------------------- 181 ; Set 'CurIndex' to the index of the next-available receive buffer, 182 ; and 'CurPacketBuf to the next-available packet buffer 183 ;------------------------------------------------------------------- 184 ;................................................................... 185 ; Get 'CurIndex' & increment it. Wrap to 0 if we reach 'NumBufs' 186 ; Since I'm treating 'CurPacketBuf' as a long integer (and not as 187 ; a segment:offset), the entire data area can't be larger than 64K. 188 ;................................................................... 189 mov dx,[CurIndex] ; DX = CurIndex 190 mov eax,[CurPacketBuf] ; EAX = current packet buffer addr 191 inc dx ; DX = next index 192 add ax,[PacketSize] ; EAX = next buffer ptr 193 cmp dx,[NumBufs] ; see if DX is past # buffers 194 jb ??Get_Flag 195 mov dx,0 ; wrap to 1st index 196 mov eax,[FirstPacketBuf] ; wrap to 1st packet buffer 197 198 ??Get_Flag: 199 ;................................................................... 200 ; Get the next buffer-in-use flag; if it's 0, load [CurIndex] with 201 ; the value of SI (the next index). If it's 1, skip the updating of 202 ; the index, flag & buffer ptr. 203 ; DX = new CurIndex 204 ; EAX = new CurPacketBuf 205 ;................................................................... 206 les di,[BufferFlags] ; ES:DI = BufferFlags address 207 mov bx,di ; BX = DI + new CurIndex 208 add bx,dx 209 210 cmp [BYTE PTR es:bx],0 ; compare next flag to 0 (avail) 211 jne ??Set_ECB ; if not avail, skip setting new values 212 213 ;................................................................... 214 ; The next buffer is available; so, set this buffer's In-Use flag 215 ; to 1, and move on to the next buffer. Do not set this buffer's 216 ; flag to 1 until we move on to the next buffer, to prevent the 217 ; application from reading the currently-in-use packet buffer. 218 ; DX = new CurIndex 219 ; EAX = new CurPacketBuf 220 ; ES:DI = BufferFlags address 221 ;................................................................... 222 mov bx,di ; BX = DI + old CurIndex 223 add bx,[CurIndex] 224 mov [BYTE PTR es:bx],1 ; set old BufferFlags value to in-use 225 226 mov [CurIndex],dx ; save new index 227 mov [CurPacketBuf],eax ; save new packet address 228 229 ;------------------------------------------------------------------- 230 ; Set up the Event Control Block to tell IPX to start listening. 231 ; The following entries are filled in by the app, and should be left 232 ; alone: 233 ; - EventServiceRoutine 234 ; - SocketNumber 235 ; The rest should be re-initialized. Note that EBX is now pointing 236 ; to an unavailable buffer if the next buffer was already in use; 237 ; so it must be reloaded with the correct buffer address from 238 ; [CurPacketBuf]. 239 ;------------------------------------------------------------------- 240 ??Set_ECB: 241 mov [ECB_LinkAddress],0 ; default 242 mov [ECB_InUse],0 ; default 243 mov [ECB_CompletionCode],0 ; default 244 mov [ECB_ConnectionID],0 ; default 245 mov [ECB_RestOfWorkspace],0 ; default 246 mov [ECB_DriverWorkSpace],0 ; default 247 mov [ECB_ImmediateAddress],0 ; default 248 mov [ECB_PacketCount],2 ; use 2 data areas 249 mov ebx,[CurPacketBuf] ; get current buffer address 250 mov [ECB_HeaderAddress],ebx ; set header address 251 mov [ECB_HeaderLength],30 ; size of IPX header 252 add ebx,30 ; point to past the header 253 mov [ECB_PacketAddress],ebx ; set packet data address 254 mov ax,[PacketSize] ; get size of one buffer 255 sub ax,30 ; remove size of IPX header 256 mov [ECB_PacketLength],ax ; set size of packet data 257 258 ;------------------------------------------------------------------- 259 ; Clear the IPX header for this packet 260 ;------------------------------------------------------------------- 261 les di,[ECB_HeaderAddress] ; ES:DI = IPX Listen Header 262 mov cx,30 ; (30 bytes = size of header) 263 mov al,0 264 rep stosb ; clear to 0's 265 266 ;------------------------------------------------------------------- 267 ; Command IPX to start listening again. 268 ;------------------------------------------------------------------- 269 mov bx,4 ; IPX code for Listen 270 mov ax,ds ; ES = segment of ListenECB 271 mov es,ax 272 mov ax,OFFSET ECB_LinkAddress 273 mov si,ax ; ES:SI = address of ECB 274 int 07ah ; call IPX interrupt 275 276 ;................................................................... 277 ; Clear our semaphore 278 ;................................................................... 279 mov [Semaphore],0 280 281 ??Exit_Handler: 282 ;................................................................... 283 ; Pop values from our local stack 284 ;................................................................... 285 pop es 286 popad 287 288 ;................................................................... 289 ; Check our stack-check value; if the stack has overflowed, generate 290 ; a debugger break. 291 ;................................................................... 292 cmp [StackCheck],1234h 293 je ??Restore_Stack 294 int 3 295 296 ;................................................................... 297 ; Restore the stack to its previous value 298 ;................................................................... 299 ??Restore_Stack: 300 lss sp, [DWORD PTR StackPtr] 301 302 ;................................................................... 303 ; Pop the rest of the registers 304 ;................................................................... 305 pop ax 306 pop ds 307 308 popf 309 310 ret 311 312 ENDP IPXHandler 313 314 END 315 316 ;************************** End of handler.asm *****************************