summaryrefslogtreecommitdiffstats
path: root/private/ntos/nbt/vxd/vnbtd.asm
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/nbt/vxd/vnbtd.asm993
1 files changed, 993 insertions, 0 deletions
diff --git a/private/ntos/nbt/vxd/vnbtd.asm b/private/ntos/nbt/vxd/vnbtd.asm
new file mode 100644
index 000000000..502f362f1
--- /dev/null
+++ b/private/ntos/nbt/vxd/vnbtd.asm
@@ -0,0 +1,993 @@
+;*****************************************************************;
+;** Copyright(c) Microsoft Corp., 1988-1993 **;
+;*****************************************************************;
+;:ts=8
+ TITLE VNBT - Netbios on TCP/IP vxd
+.XLIST
+;*** VNBT -- NetBios on TCP/IP VxD
+;
+; This module contains the device header for the NBT VxD driver.
+;
+ .386p
+ include vmm.inc
+ifdef CHICAGO
+ include ndis.inc
+endif ;; CHICAGO
+ include dosmgr.inc
+ include netvxd.inc
+IFDEF CHICAGO
+ include configmg.inc
+ENDIF
+ include vwin32.inc
+ include vdhcp.inc
+ include debug.inc
+ include vtdi.inc
+
+ Create_VNBT_Service_Table EQU True
+ifdef CHICAGO
+ include vnbt.inc
+else ;; CHICAGO
+ include vnbtd.inc
+endif ;; CHICAGO
+ include vnetbios.inc
+
+ include pageable.inc
+.LIST
+
+Declare_Virtual_Device VNBT,3,0,VNBT_Control,VNBT_Device_ID, \
+ VNBT_Init_Order,VNBT_Api_Handler,VNBT_Api_Handler
+
+
+VxD_DATA_SEG
+VxD_DATA_ENDS
+
+EXTRN __VxdMapSegmentOffsetToFlat:near ; from client.asm
+ifndef CHICAGO
+EXTRN _BSSBegin:DWORD
+EXTRN _BSSDataEnd:DWORD
+endif ;; CHICAGO
+EXTRN _TdiDispatch:DWORD
+
+EXTRN _PostInit_Proc:NEAR
+EXTRN _VxdApiWorker:NEAR
+
+ifndef CHICAGO
+EXTRN _VNBT_NCB_X@20:NEAR
+endif ;; CHICAGO
+
+EXTRN _GetDhcpOption:NEAR
+
+
+VxD_ICODE_SEG
+
+EXTRN _Init:NEAR
+
+MSTCP db 'MSTCP',0 ; Protocol this driver sits on (this will have
+ ; to be changed to get it from an .ini file)
+IFDEF CHICAGO
+bInitialized db 0 ; 0 means not initialized, 1 means we've entered
+ ; the initialization, and 2 means we've left init
+bSuccessInit db 0 ; 0 means initialization failed and all subsequent
+ ; initializations should fail
+ENDIF
+
+NBTSectionName db 'NBT',0 ; Section where parameters are stored
+
+;****************************************************************************
+;** VNBT_Device_Init - VNBT device initialization service.
+;
+; The VNBT device initialization routine. Before calling anything
+; we need to zero out the BSS data area.
+;
+;
+; Entry: (EBX) - System VM Handle
+; (EBP) - System Client Regs structure.
+;
+; Exit: 'CY' clear if we init. successfully.
+; 'CY' set if we've failed.
+;
+BeginProc VNBT_Device_Init
+
+IFDEF CHICAGO
+ ;
+ ; Chicago calls us at both dynamic and static init, so only process
+ ; once
+ ;
+ cmp bInitialized, 2 ; 2 means we've already completed initialization
+ jne Init_Continue
+ clc ; Assume success (is checked below)
+ jmp Init_Exit
+
+Init_Continue:
+ mov bInitialized, 1
+ENDIF
+
+ifndef CHICAGO
+ mov edi, OFFSET32 _BSSBegin
+ mov ecx, OFFSET32 _BSSDataEnd
+ sub ecx, edi
+ shr ecx, 2
+ sub eax, eax
+ cld
+ rep stosd
+endif ;; CHICAGO
+
+ VxDcall VTDI_Get_Version
+ jc Init_Exit ; Get out if VTDI is not installed
+
+ ;
+ ; Get the TDI Vxd dispatch table for "MSTCP" to initialize the TDI
+ ; dispatch table (which will be needed by some of our
+ ; initialization stuff)
+ ;
+ mov eax, OFFSET32 MSTCP
+ push eax
+ VxDcall VTDI_Get_Info
+ add esp, 4
+ cmp eax, 0 ; eax contains NULL or the pointer to the table
+ jne NoError
+
+ Debug_Out "VNBT_Device_Init - VTDI_Get_Info failed!"
+ stc ; Set the carry
+ jmp Init_Exit
+
+NoError:
+ mov _TdiDispatch, eax
+
+ ;
+ ; Initialize the rest of the driver
+ ;
+ call _Init
+ cmp eax, 1 ; Set 'CY' appropriately.
+
+Init_Exit:
+
+IFDEF CHICAGO
+ jc Exit2 ; Failed init, leave bSuccessInit 0
+
+ ;
+ ; If first time through and success, indicate successful initialization
+ ;
+ cmp bInitialized, 1
+ je SetInitFlag
+
+ ;
+ ; We've already been initialized once, was it successful?
+ ;
+ cmp bSuccessInit, 1
+ clc ; test clears the carry so assume success
+ je Exit2
+
+ stc ; Set the carry since we failed init. last time
+ jmp Exit2
+
+SetInitFlag:
+ clc
+ mov bSuccessInit, 1
+
+Exit2:
+ mov bInitialized, 2
+ENDIF
+ ret
+
+
+
+
+EndProc VNBT_Device_Init
+
+
+VxD_ICODE_ENDS
+
+NBT_PAGEABLE_CODE_SEG
+
+ifdef CHICAGO
+_NdisOpenProtocolConfiguration@12 PROC NEAR PUBLIC
+ VxDJmp NdisOpenProtocolConfiguration
+_NdisOpenProtocolConfiguration@12 ENDP
+
+_NdisCloseConfiguration@4 PROC NEAR PUBLIC
+ VxDJmp NdisCloseConfiguration
+_NdisCloseConfiguration@4 ENDP
+
+_NdisReadConfiguration@20 PROC NEAR PUBLIC
+ VxDJmp NdisReadConfiguration
+_NdisReadConfiguration@20 ENDP
+endif ;; CHICAGO
+
+NBT_PAGEABLE_CODE_ENDS
+
+VxD_CODE_SEG
+;****************************************************************************
+;* NCB_Handler
+;
+; Called by VNetBios when NCBs need to be submitted to this driver
+;
+; ENTRY:
+; EBX = NCB being submitted
+;
+; EXIT:
+; AL - return code
+;
+BeginProc NCB_Handler
+
+ ;
+ ; In the master portion of the mif tests, after hitting ctrl-c during
+ ; the attempt to synchronize, a wait add group name NCB is
+ ; submitted with interrupts disabled. The CTE timer event handler
+ ; checks this and schedules an event for when they are re-enabled,
+ ; however since it's a wait NCB, we deadlock in VNBT_NCB_X's block.
+ ;
+ ; Make sure interrupts are enabled.
+ ; BUGBUG - Why were we called with ints disabled?
+ ;
+ ;VMMcall Enable_VM_Ints
+
+ xor eax, eax ; second parm of VNBT_NCB_X is unused when
+
+ifndef CHICAGO
+
+ push eax
+ push eax
+ push eax ; called from here, but is used (e.g.nbtstat)
+ push eax
+ push ebx
+ call _VNBT_NCB_X@20 ; when VNBT_NCB_X is called directly
+
+else ;; CHICAGO
+if 0
+;
+; As of 08-Feb-1996 there is a bug in "vmm.h" where this doesn't
+; work properly, with the result being a misaligned stack pointer.
+;
+ VxDCall VNBT_NCB_X, <ebx, eax, eax, eax, eax>
+else ;; 0
+ push eax
+ push eax
+ push eax
+ push eax
+ push ebx
+ VxDCall VNBT_NCB_X
+endif ;; 0
+endif ;; CHICAGO
+
+ ret
+EndProc NCB_Handler
+
+;****************************************************************************
+;** _DhcpQueryOption - Queries a DHCP option
+;
+; Stub callout to the Dhcp driver
+;
+; Entry: [ESP+4] - IP Address of interest
+; [ESP+8] - DHCP Option number
+; [ESP+12]- Pointer to buffer
+; [ESP+16]- Pointer to buffer size
+;
+;
+
+BeginProc _DhcpQueryOption
+
+ VxdCall VDHCP_Get_Version
+ jnc DQI_Installed
+
+ mov eax, 26 ; DHCP not installed, return invalid param
+ ret
+
+DQI_Installed:
+ push ebp
+ mov ebp,esp
+
+ mov eax, [ebp+20] ; Buff size
+ push eax
+ mov eax, [ebp+16] ; Buff
+ push eax
+ mov eax, [ebp+12] ; Option
+ push eax
+ mov eax, [ebp+8] ; IP Address
+ push eax
+
+ VxdCall VDHCP_Query_Option
+
+ add esp, 16
+
+ pop ebp
+ ret
+
+EndProc _DhcpQueryOption
+
+;****************************************************************************
+;** VNBT_Get_Version - VNBT get version service
+;
+; Called by using devices to make sure the VNBT driver
+; is present. Also returns the version of the VNBT driver.
+;
+; Entry: Nothing
+;
+; Exit: On success, 'CY' is clear, and
+; AH - Major version # of driver.
+; AL - Minor version #
+;
+; On failure, 'CY' is set.
+;
+; Uses: AX
+;
+BeginProc VNBT_Get_Version, SERVICE
+
+ mov ax, VNBT_VERSION
+ clc
+ ret
+
+EndProc VNBT_Get_Version
+
+VxD_CODE_ENDS
+NBT_PAGEABLE_CODE_SEG
+
+;****************************************************************************
+;** VNBT_Device_PostProc - do postprocessing
+;
+; Called by the sytem when all the other stuff (in our case, rdr) is
+; loaded. At this we read the lmhosts file, so that any #INCLUDE with
+; UNC names in it will work.
+; This routine can also be used for other stuff, but for now only lmhosts
+; stuff.
+;
+BeginProc VNBT_Device_PostProc
+
+ call _PostInit_Proc
+ clc
+ ret
+
+EndProc VNBT_Device_PostProc
+
+NBT_PAGEABLE_CODE_ENDS
+VxD_CODE_SEG
+
+;****************************************************************************
+;** VNBT_Control - VNBT device control procedure
+;
+; This procedure dispatches VxD messages to the appropriate handler.
+;
+; Entry: EBX - VM handle
+; (EBP) - Client reg structure
+;
+; Exit: 'NC' is success, 'CY' on failure
+;
+; Uses: All
+;
+BeginProc VNBT_Control
+
+ Control_Dispatch Device_Init, VNBT_Device_Init
+ Control_Dispatch Sys_Dynamic_Device_Init, VNBT_Device_Init
+ Control_Dispatch Sys_Vm_Init, VNBT_Device_PostProc
+IFDEF CHICAGO
+ Control_Dispatch W32_DEVICEIOCONTROL, VNBT_DeviceIoControl
+ENDIF
+
+ clc
+ ret
+
+EndProc VNBT_Control
+
+IFDEF CHICAGO
+;*******************************************************************
+;** VNBT_DeviceIoControl
+;
+; Dispatch routine for VxD services invoked via the Win32
+; DeviceIoControl API.
+;
+; Entry: (ESI) - Points to DIOCParams structure (see VWIN32.H).
+;
+; Exit: (EAX) - Win32 status code, -1 for asynchronous
+; completion.
+; HISTORY:
+; Koti 10-Nov-1994 Created (Modified from wsock version)
+;
+;********************************************************************
+BeginProc VNBT_DeviceIoControl
+
+;;;
+;;; Setup stack frame.
+;;;
+
+ push ebx
+ push esi
+ push edi
+
+ mov eax, [esi.dwIoControlCode]
+ cmp ecx, DIOC_GETVERSION
+ je vdic_doNothing
+ cmp ecx, DIOC_CLOSEHANDLE
+ jne vdic_doSomething
+
+;;;
+;;; For devioctl calls resulting from CreateFile and CloseFile, we don't do
+;;; anything other than return success.
+;;;
+
+vdic_doNothing:
+ xor eax, eax
+ jmp vdic_CommonExit
+
+;;;
+;;; This is an ioctl requiring some work: call our api worker (VxdApiWorker)
+;;;
+
+vdic_doSomething:
+
+;;; Lock the in-buffer.
+
+ mov eax, [esi.lpvInBuffer]
+ or eax, eax
+ jz vdic_outbuf
+
+ cCall __VxdLockBuffer, <eax, [esi.cbInBuffer]>
+ or eax, eax
+ jz vdic_LockFailure
+ mov [esi.lpvInBuffer], eax
+
+vdic_outbuf:
+
+;;; Lock the out-buffer.
+
+ mov eax, [esi.lpvOutBuffer]
+ or eax, eax
+ jz vdic_callApi
+
+ cCall __VxdLockBuffer, <eax, [esi.cbOutBuffer]>
+ or eax, eax
+ jz vdic_LockFailure
+ mov [esi.lpvOutBuffer], eax
+
+vdic_callApi:
+
+ mov eax, 0 ; VxdApiWorker won't trash input buffer
+ push eax
+ mov eax, [esi.cbInBuffer]
+ push eax
+ mov eax, [esi.lpvInBuffer]
+ push eax
+ mov eax, [esi.cbOutBuffer]
+ push eax
+ mov eax, [esi.lpvOutBuffer]
+ push eax
+ mov eax, [esi.dwIoControlCode]
+ push eax
+
+ call _VxdApiWorker
+ add esp, 24
+
+
+;;; Unlock the in-buffer.
+
+ push eax ; save the return code from VxdApiWorker
+ cCall __VxdUnlockBuffer, <[esi.lpvInBuffer], [esi.cbInBuffer]>
+ pop eax
+
+;;; Unlock the out-buffer.
+
+ push eax ; save the return code from VxdApiWorker
+ cCall __VxdUnlockBuffer, <[esi.lpvOutBuffer], [esi.cbOutBuffer]>
+ pop eax
+
+vdic_CommonExit:
+
+ pop edi
+ pop esi
+ pop ebx
+
+ ret
+
+;;;
+;;; Failed to lock parameter structure.
+;;;
+
+vdic_LockFailure:
+
+ Debug_Out "VNBT_DeviceIoControl: cannot lock parameters"
+
+ mov eax, 1784 ; ERROR_INVALID_USER_BUFFER
+ jmp vdic_CommonExit
+
+EndProc VNBT_DeviceIoControl
+
+;*******************************************************************
+;** _ReconfigureDevnode
+;
+; This routine schedules an AppyTime call for the ConfigMgr to
+; call us back when it's ready. It calls our routine VNBT_ConfigCalls
+;
+; Entry: ESP+4 our devnode on the stack
+;
+; Exit: (EAX) - 0 if everything goes well
+; 1 if something goes wrong
+;
+; HISTORY:
+; Koti 15-Dec-1994 Created
+;
+;********************************************************************
+
+BeginProc _ReconfigureDevnode
+
+ push ebp
+ mov ebp, esp
+
+ xor eax, eax
+ push eax ; the flags
+ mov eax, [ebp+8] ; our devnode
+ push eax ; this is our RefData
+ lea eax, VNBT_ConfigCalls ; call back routine
+ push eax
+ VxdCall _CONFIGMG_Call_At_Appy_Time
+ add esp, 12
+ cmp eax, CR_SUCCESS
+ je ReconfigureDevnode_PASS
+ mov eax, 1
+ jmp ReconfigureDevnode_Exit
+
+ReconfigureDevnode_PASS:
+ xor eax, eax
+
+ReconfigureDevnode_Exit:
+IFDEF DBG
+ or eax, eax
+ jz ReconfigureDevnode_GoodJob
+ int 3
+ReconfigureDevnode_GoodJob:
+ENDIF
+ pop ebp
+ ret
+EndProc _ReconfigureDevnode
+
+VxD_CODE_ENDS
+
+NBT_PAGEABLE_CODE_SEG
+
+;*******************************************************************
+;** VNBT_ConfigCalls
+;
+; This routine makes all the calls to the Config Mgr so that our
+; devnode is reconfigured. We first get vredir's devnode, kill it
+; and then reenumerate all the children again. This way vredir
+; gets the msg from ConfigMgr to do whatever it does with a new devnode.
+;
+; If dhcp lease expires and then comes back in, vredir had no way
+; of knowing that lana is usable again: hence this convoluted way.
+;
+; IMPORTANT: if chicago ever changes to add more children to tcp's
+; devnode, this function needs to be modified to enumerate
+; rest of the children and kill them!
+;
+; Entry: (EDX) - our devnode
+;
+; Exit: (EAX) - 0 if everything goes well
+; 1 if something goes wrong
+;
+; HISTORY:
+; Koti 15-Dec-1994 Created
+;
+;********************************************************************
+
+VnbtScratch dd 0
+
+BeginProc VNBT_ConfigCalls
+
+ push ebp
+ mov ebp, esp
+ push esi
+ push edi
+ push ecx
+
+ ;;; First get the first child
+ xor eax, eax
+ push eax ; the flags
+ mov eax, [ebp+8]
+ push eax ; our devnode
+ lea eax, VnbtScratch ; this is where we will receive child node
+ push eax
+ VxdCall _CONFIGMG_Get_Child
+ add esp, 12
+ mov esi, dword ptr [VnbtScratch] ;save the first child in esi
+ mov edi, 0 ; for now, make esi,edi different
+ cmp eax, CR_SUCCESS
+ je ConfigCalls_Label2
+ mov ecx, 1
+ jmp ConfigCalls_Exit
+
+ ;;; Get a sibling of this child
+ConfigCalls_Label2:
+ cmp edi, esi ; did we just kill the first child
+ je ConfigCalls_Label6 ; yes: we are done with all the killings
+ xor eax, eax
+ push eax ; the flags
+ push esi ; the first child
+ lea eax, VnbtScratch ; this is where we will receive sibling
+ push eax
+ VxdCall _CONFIGMG_Get_Sibling
+ add esp, 12
+ mov edi, dword ptr [VnbtScratch] ;edi contains sibling
+ cmp eax, CR_SUCCESS ; found a sibling?
+ je ConfigCalls_Label4 ; yes, go kill it
+ cmp eax, CR_NO_SUCH_DEVNODE ; done with all siblings?
+ je ConfigCalls_Label3 ; yes, go kill the first child
+ mov ecx, 2 ; hmmm: something went wrong
+ jmp ConfigCalls_Exit
+
+ ;;; Done with all the siblings: now kill the first child
+ConfigCalls_Label3:
+ mov edi, esi ; esi=first child, edi=child to kill
+
+ConfigCalls_Label4:
+ ;;; Now, ask ConfigMgr if it's ok to kill our child
+ xor eax, eax
+ push eax ; the flags
+ push edi ; sibling's devnode
+ VxdCall _CONFIGMG_Query_Remove_SubTree
+ add esp, 8
+ cmp eax, CR_SUCCESS ; ok to kill?
+ je ConfigCalls_Label5 ; nope!
+ mov ecx, 4
+ jmp ConfigCalls_Exit
+
+ConfigCalls_Label5:
+ ;;; Now that ConfigMgr approved, kill the child
+ xor eax, eax
+ push eax ; the flags
+ push edi ; sibling's devnode
+ VxdCall _CONFIGMG_Remove_SubTree
+ add esp, 8
+ cmp eax, CR_SUCCESS ; did it die?
+ je ConfigCalls_Label2 ; yes, it did: go kill other siblings
+ mov ecx, 5 ; nope!
+ jmp ConfigCalls_Exit
+
+ConfigCalls_Label6:
+ ;;; Ok, reenumerate our devnode so our children come back to life
+ xor eax, eax
+ push eax ; the flags
+ mov eax, [ebp+8]
+ push eax ; our devnode
+ VxdCall _CONFIGMG_Reenumerate_DevNode
+ add esp, 8
+ cmp eax, CR_SUCCESS ; did it die?
+ je ConfigCalls_Label7 ; nope!
+ mov ecx, 6
+ jmp ConfigCalls_Exit
+
+ConfigCalls_Label7:
+ xor eax, eax
+
+ConfigCalls_Exit:
+IFDEF DBG
+ or eax, eax
+ jz ConfigCalls_GoodJob
+ int 3
+ConfigCalls_GoodJob:
+ENDIF
+ pop ecx
+ pop edi
+ pop esi
+ pop ebp
+ ret
+EndProc VNBT_ConfigCalls
+
+ENDIF
+
+NBT_PAGEABLE_CODE_ENDS
+
+VxD_CODE_SEG
+
+;****************************************************************************
+;** _GetInDosFlag - Retrieves the InDos flag
+;
+;
+; Note: This routine cannot be called at init time (vdosmgr complains
+; the variable not initialized yet)
+;
+; Returns the flag in ax
+;
+
+BeginProc _GetInDosFlag
+
+ push ebx
+
+ VxdCall DOSMGR_Get_IndosPtr
+
+ ;
+ ; Add CB_High_Linear if we are in V86 mode
+ ;
+
+ VMMcall Get_Cur_VM_Handle
+
+ test [ebx.CB_VM_Status], VMStat_PM_Exec
+ jnz GIF_Exit
+
+ add eax, [ebx.CB_High_Linear]
+
+GIF_Exit:
+ movzx eax, word ptr [eax]
+
+ pop ebx
+ ret
+EndProc _GetInDosFlag
+
+;****************************************************************************
+;
+; ULONG
+; RtlCompareMemory (
+; IN PVOID Source1,
+; IN PVOID Source2,
+; IN ULONG Length
+; )
+;
+; Routine Description:
+;
+; This function compares two blocks of memory and returns the number
+; of bytes that compared equal.
+;
+; Arguments:
+;
+; Source1 (ebp+8) - Supplies a pointer to the first block of memory to
+; compare.
+;
+; Source2 (ebp+12) - Supplies a pointer to the second block of memory to
+; compare.
+;
+; Length (ebp+16) - Supplies the Length, in bytes, of the memory to be
+; compared.
+;
+; Return Value:
+;
+; The number of bytes that compared equal is returned as the function
+; value. If all bytes compared equal, then the length of the orginal
+; block of memory is returned.
+;
+;--
+
+RcmSource1 equ [ebp+8]
+RcmSource2 equ [ebp+12]
+RcmLength equ [ebp+16]
+
+public _VxdRtlCompareMemory
+BeginProc _VxdRtlCompareMemory
+
+ push ebp
+ mov ebp,esp
+ push esi
+ push edi
+ cld
+
+ mov esi,RcmSource1 ; (esi) -> first block to compare
+ mov edi,RcmSource2 ; (edi) -> second block to compare
+ mov ecx,RcmLength ; (ecx) = length in bytes
+ and ecx,3 ; (ecx) = length mod 4
+ jz rcm10 ; 0 odd bytes, go do dwords
+
+;
+; Compare "odd" bytes.
+;
+
+ repe cmpsb ; compare odd bytes
+ jnz rcm40 ; mismatch, go report how far we got
+
+;
+; Compare dwords.
+;
+
+rcm10: mov ecx,RcmLength ; (ecx) = length in bytes
+ shr ecx,2 ; (ecx) = length in dwords
+ jz rcm20 ; no dwords, go exit
+
+ repe cmpsd ; compare dwords
+ jnz rcm30 ; mismatch, go find byte
+
+;
+; When we come to rcm20, we matched all the way to the end. Esi
+; points to the byte after the last byte in the block, so Esi - RcmSource1
+; equals the number of bytes that matched
+;
+
+rcm20: sub esi,RcmSource1
+ mov eax,esi
+ pop edi
+ pop esi
+ pop ebp
+ ret
+
+;
+; When we come to rcm30, esi (and edi) points to the dword after the
+; one which caused the mismatch. Back up 1 dword and find the byte.
+; Since we know the dword didn't match, we can assume one byte won't.
+;
+
+rcm30: sub esi,4 ; back up
+ sub edi,4 ; back up
+ mov ecx,5 ; ensure that ecx doesn't count out
+ repe cmpsb ; find mismatch byte
+
+;
+; When we come to rcm40, esi points to the byte after the one that
+; did not match, which is TWO after the last byte that did match.
+;
+
+rcm40: dec esi
+ sub esi,RcmSource1
+ mov eax,esi
+ pop edi
+ pop esi
+ pop ebp
+ ret
+
+EndProc _VxdRtlCompareMemory
+
+;****************************************************************************
+;** VNBT_Api_Handler - handles all request from other vxd's, v86-mode apps
+;
+; This procedure does all the address translations, memory locking etc.
+; and calls the C routine VxdApiWorker() to do the actual work
+;
+; Entry: EBX - VM handle
+; (EBP) - Client reg structure
+;
+; Exit: 'NC' is success, 'CY' on failure
+;
+; Uses: All
+;
+; HISTORY:
+; Koti 16-Jun-1994 Created (Modified from dhcp's version)
+;
+;********************************************************************
+BeginProc VNBT_Api_Handler
+
+
+ push ebp
+ push ebx
+ push esi
+ push edi
+ push edx
+ push ecx
+
+;;; get function op code
+
+ movzx edi, [ebp.Client_CX]
+
+;;;
+;;; Convert the parameter buffer pointers from segmented to flat.
+;;;
+
+;;; first, the output buffer
+
+ movzx eax, [ebp.Client_BX]
+ push eax
+ movzx eax, [ebp.Client_ES]
+ push eax
+ push ebx
+ call __VxdMapSegmentOffsetToFlat
+ add esp, 12
+
+ cmp eax, 0FFFFFFFFh
+ je vnbt_Fault
+
+;;;
+;;; Lock the output buffer.
+;;;
+
+ or eax, eax
+ jz vnbt_DontLock_OutBuf
+
+ movzx ecx, [ebp.Client_DI]
+ cCall __VxdLockBuffer, <eax, ecx>
+
+ or eax, eax
+ jz vnbt_Fault
+
+vnbt_DontLock_OutBuf:
+
+ mov esi, eax
+
+;;; now, convert and lock the input buffer
+
+ movzx eax, [ebp.Client_AX]
+ push eax
+ movzx eax, [ebp.Client_DX]
+ push eax
+ push ebx
+ call __VxdMapSegmentOffsetToFlat
+ add esp, 12
+
+ cmp eax, 0FFFFFFFFh
+ je vnbt_Fault
+
+ or eax, eax
+ jz vnbt_DontLock
+
+ movzx ebx, [ebp.Client_SI]
+ cCall __VxdLockBuffer, <eax, ebx> ; this preserves esi
+
+ or eax, eax
+ jz vnbt_Fault
+
+vnbt_DontLock:
+
+ mov edx, eax
+
+;;; call worker routine
+;;; edi - opcode
+;;; esi - OutBuffer pointer
+;;; ecx - OutBuffer length
+;;; edx - InBuffer pointer
+;;; ebx - InBuffer length
+
+;
+; RLF 05/30/94 - __VxdLockBuffer destroys contents of cx - reload
+;
+
+ push esi ; save OutBuffer addr
+ push edx ; save InBuffer addr
+
+ mov eax, 1 ; VxdApiWorker will trash input buffer
+ push eax
+ movzx ecx, [ebp.Client_DI]
+ movzx ebx, [ebp.Client_SI]
+ push ebx
+ push edx
+ push ecx
+ push esi
+ push edi
+
+ call _VxdApiWorker
+ add esp, 24
+
+ pop edx ; restore InBuffer addr
+ pop esi ; restore OutBuffer addr
+
+ mov [ebp.Client_AX], ax
+
+;;;
+;;; Unlock the parameter buffer.
+;;;
+
+ or esi, esi
+ jz vnbt_DontUnLock_OutBuf
+
+ push edx ; save InBuffer addr
+ movzx ecx, [ebp.Client_DI]
+ cCall __VxdUnlockBuffer <esi, ecx>
+ pop edx ; restore InBuffer addr
+vnbt_DontUnLock_OutBuf:
+
+ or edx, edx
+ jz vnbt_DontUnLock
+
+ movzx ebx, [ebp.Client_SI]
+ cCall __VxdUnlockBuffer <edx, ebx>
+
+vnbt_DontUnLock:
+
+vnbt_CommonExit:
+
+;;; Restore stack fame
+ pop ecx
+ pop edx
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+;;;
+;;; Either failed to map a segmented pointer to flat or failed
+;;; to lock the parameter buffer.
+;;;
+
+vnbt_Fault:
+
+ cmp eax, 0FFFFFFFFh
+ mov [ebp.Client_AX], ax
+ jmp vnbt_CommonExit
+
+
+EndProc VNBT_Api_Handler
+
+VxD_CODE_ENDS
+END
+