;*****************************************************************; ;** 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, 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, 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, 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, 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, ; 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 pop edx ; restore InBuffer addr vnbt_DontUnLock_OutBuf: or edx, edx jz vnbt_DontUnLock movzx ebx, [ebp.Client_SI] cCall __VxdUnlockBuffer 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