/*++ Copyright (c) 1989-1993 Microsoft Corporation Module Name: Driver.c Abstract: This module implements the DRIVER_INITIALIZATION routine for the NBT Transport and other routines that are specific to the NT implementation of a driver. Author: Jim Stewart (Jimst) 10-2-92 Revision History: --*/ #include "precomp.h" #include #include "driver.tmh" #if DBG // allocate storage for the global debug flag NbtDebug //ULONG NbtDebug = NBT_DEBUG_KDPRINTS| NBT_DEBUG_NETBIOS_EX; ULONG NbtDebug = 0; #endif // DBG NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); NTSTATUS NbtDispatchCleanup( IN PDEVICE_OBJECT Device, IN PIRP pIrp ); NTSTATUS NbtDispatchClose( IN PDEVICE_OBJECT device, IN PIRP pIrp ); NTSTATUS NbtDispatchCreate( IN PDEVICE_OBJECT Device, IN PIRP pIrp ); NTSTATUS NbtDispatchDevCtrl( IN PDEVICE_OBJECT device, IN PIRP pIrp ); NTSTATUS NbtDispatchInternalCtrl( IN PDEVICE_OBJECT device, IN PIRP pIrp ); #ifdef _PNP_POWER_ VOID NbtUnload( IN PDRIVER_OBJECT device ); #endif // _PNP_POWER_ NTSTATUS NbtDispatchPnP( IN PDEVICE_OBJECT Device, IN PIRP pIrp ); PFILE_FULL_EA_INFORMATION FindInEA( IN PFILE_FULL_EA_INFORMATION start, IN PCHAR wanted ); VOID ReturnIrp( IN PIRP pIrp, IN int status ); VOID MakePending( IN PIRP pIrp ); NTSTATUS NbtCreateAdminSecurityDescriptor( IN PDEVICE_OBJECT dev ); #ifdef _PNP_POWER_DBG_ // //Debug Stuff for DbgBreakPoint -- REMOVE // NTSTATUS NbtOpenRegistry( IN HANDLE NbConfigHandle, IN PWSTR String, OUT PHANDLE pHandle ); #endif // _PNP_POWER_DBG_ #ifdef _PNP_POWER_ HANDLE TdiClientHandle = NULL; HANDLE TdiProviderHandle = NULL; extern tTIMERQ TimerQ; #endif // _PNP_POWER_ #ifdef _NETBIOSLESS tDEVICECONTEXT *pNbtSmbDevice = NULL; #endif // _NETBIOSLESS //******************* Pageable Routine Declarations **************** #ifdef ALLOC_PRAGMA #pragma CTEMakePageable(INIT, DriverEntry) #pragma CTEMakePageable(PAGE, NbtDispatchCleanup) #pragma CTEMakePageable(PAGE, NbtDispatchClose) #pragma CTEMakePageable(PAGE, NbtDispatchCreate) #pragma CTEMakePageable(PAGE, NbtDispatchDevCtrl) #pragma CTEMakePageable(PAGE, FindInEA) #pragma CTEMakePageable(PAGE, NbtUnload) #endif //******************* Pageable Routine Declarations **************** //---------------------------------------------------------------------------- VOID CleanupDriverEntry( ULONG CleanupStage ) { PSINGLE_LIST_ENTRY pSingleListEntry; PMDL pMdl; PVOID pBuffer; LIST_ENTRY *pListEntry; tDGRAM_SEND_TRACKING *pTracker; switch (CleanupStage) { case (6): NbtDestroyDevice (pWinsDeviceContext, FALSE); #ifdef RASAUTODIAL // // Unbind fron the RAS driver if we were bound // NbtAcdUnbind (); #endif // RASAUTODIAL // Fall through case (5): if (pNbtSmbDevice) { NbtDestroyDevice (pNbtSmbDevice, FALSE); pNbtSmbDevice = NULL; } if (NbtConfig.OutOfRsrc.pDpc) { CTEMemFree (NbtConfig.OutOfRsrc.pDpc); } if (NbtConfig.OutOfRsrc.pIrp) { IoFreeIrp (NbtConfig.OutOfRsrc.pIrp); } // Fall through case (4): while (NbtConfig.SessionMdlFreeSingleList.Next) { pSingleListEntry = PopEntryList(&NbtConfig.SessionMdlFreeSingleList); pMdl = CONTAINING_RECORD(pSingleListEntry,MDL,Next); pBuffer = MmGetMdlVirtualAddress (pMdl); CTEMemFree (pBuffer); IoFreeMdl (pMdl); } while (NbtConfig.DgramMdlFreeSingleList.Next) { pSingleListEntry = PopEntryList(&NbtConfig.DgramMdlFreeSingleList); pMdl = CONTAINING_RECORD(pSingleListEntry,MDL,Next); pBuffer = MmGetMdlVirtualAddress (pMdl); CTEMemFree (pBuffer); IoFreeMdl (pMdl); } // Fall through case (3): // // InitNotOs has been called // DestroyTimerQ(); while (!IsListEmpty(&NbtConfig.DgramTrackerFreeQ)) { pListEntry = RemoveHeadList(&NbtConfig.DgramTrackerFreeQ); pTracker = CONTAINING_RECORD(pListEntry,tDGRAM_SEND_TRACKING,Linkage); CTEMemFree (pTracker); } DestroyHashTables (); ExDeleteResourceLite (&NbtConfig.Resource); // Delete the resource // Fall through case (2): // // Read registry has been called! // CTEMemFree (NbtConfig.pLmHosts); CTEMemFree (NbtConfig.pScope); if (NbtConfig.pTcpBindName) { CTEMemFree (NbtConfig.pTcpBindName); } // Fall through case (1): CTEMemFree (NbtConfig.pRegistry.Buffer); default: break; } } //---------------------------------------------------------------------------- NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This is the initialization routine for the NBT device driver. This routine creates the device object for the NBT device and calls a routine to perform other driver initialization. Arguments: DriverObject - Pointer to driver object created by the system. Return Value: NTSTATUS - The function value is the final status from the initialization operation. --*/ { NTSTATUS status; tDEVICES *pBindDevices=NULL; tDEVICES *pExportDevices=NULL; tADDRARRAY *pAddrArray=NULL; PMDL pMdl; PSINGLE_LIST_ENTRY pSingleListEntry; UNICODE_STRING ucWinsDeviceBindName; UNICODE_STRING ucWinsDeviceExportName; UNICODE_STRING ucSmbDeviceBindName; UNICODE_STRING ucSmbDeviceExportName; UNICODE_STRING ucNetBTClientName; UNICODE_STRING ucNetBTProviderName; TDI_CLIENT_INTERFACE_INFO TdiClientInterface; #ifdef _PNP_POWER_DBG_ // //Debug Stuff for DbgBreakPoint // OBJECT_ATTRIBUTES TmpObjectAttributes; HANDLE NbtConfigHandle; ULONG Disposition; PWSTR ParametersString = L"Parameters"; HANDLE ParametersHandle; #endif // _PNP_POWER_DBG_ CTEPagedCode(); #ifdef _NBT_WMI_SOFTWARE_TRACING_ WPP_INIT_TRACING(DriverObject, RegistryPath); #endif #ifdef _PNP_POWER_DBG_ InitializeObjectAttributes (&TmpObjectAttributes, RegistryPath, // name OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes NULL, // root NULL); // security descriptor status = ZwCreateKey (&NbtConfigHandle, KEY_READ, &TmpObjectAttributes, 0, // title index NULL, // class 0, // create options &Disposition); // disposition if (!NT_SUCCESS(status)) { NbtLogEvent (EVENT_NBT_CREATE_DRIVER, status, 0x109); return STATUS_UNSUCCESSFUL; } status = NbtOpenRegistry (NbtConfigHandle, ParametersString, &ParametersHandle); if (!NT_SUCCESS(status)) { ZwClose(NbtConfigHandle); return (status); } if (CTEReadSingleIntParameter(ParametersHandle, ANSI_IF_VXD("Break"), 0, 0)) // disabled by default { KdPrint (("Nbt.DriverEntry: Registry-set Break!\n")); DbgBreakPoint(); } ZwClose(ParametersHandle); ZwClose(NbtConfigHandle); #endif // _PNP_POWER_DBG_ TdiInitialize(); // // get the file system process for NBT since we need to know this for // allocating and freeing handles // NbtFspProcess =(PEPROCESS)PsGetCurrentProcess(); // // Initialize the Configuration data structure // CTEZeroMemory(&NbtConfig,sizeof(tNBTCONFIG)); NbtConfig.LoopbackIfContext = 0xffff; // save the driver object for event logging purposes // NbtConfig.DriverObject = DriverObject; // save the registry path for later use when DHCP asks us // to re-read the registry. // NbtConfig.pRegistry.MaximumLength = (USHORT) RegistryPath->MaximumLength; if (NbtConfig.pRegistry.Buffer = NbtAllocMem (RegistryPath->MaximumLength, NBT_TAG2('17'))) { RtlCopyUnicodeString(&NbtConfig.pRegistry,RegistryPath); } else { return (STATUS_INSUFFICIENT_RESOURCES); } // // Initialize the driver object with this driver's entry points. // DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)NbtDispatchCreate; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)NbtDispatchDevCtrl; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)NbtDispatchInternalCtrl; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)NbtDispatchCleanup; DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)NbtDispatchClose; DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)NbtDispatchPnP; DriverObject->DriverUnload = NbtUnload; // // read in registry configuration data // status = NbtReadRegistry (&pBindDevices, &pExportDevices, &pAddrArray); if (!NT_SUCCESS(status)) { // // There must have been some major problems with the registry, so // we will not load! // DbgPrint ("Nbt.DriverEntry[1]: Not loading because of failure to read registry = <%x>\n", status); CleanupDriverEntry (1); return(status); } // // Cleanup Allocated memory // NbtReadRegistryCleanup (&pBindDevices, &pExportDevices, &pAddrArray); // // Initialize NBT global data. // status = InitNotOs(); if (!NT_SUCCESS(status)) { NbtLogEvent (EVENT_NBT_NON_OS_INIT, status, 0x110); DbgPrint ("Nbt.DriverEntry[3]: Not loading because of failure to Initialize = <%x>\n",status); CleanupDriverEntry (3); // We may have done some partial initialization! return (status); } // create some MDLs, for session sends to speed up the sends. status = NbtInitMdlQ (&NbtConfig.SessionMdlFreeSingleList, eNBT_FREE_SESSION_MDLS); if (!NT_SUCCESS(status)) { DbgPrint ("Nbt.DriverEntry[4]: Not loading because of failure to init Session MDL Q = <%x>\n",status); CleanupDriverEntry (4); return (status); } // create some MDLs for datagram sends status = NbtInitMdlQ( &NbtConfig.DgramMdlFreeSingleList, eNBT_DGRAM_MDLS); if (!NT_SUCCESS(status)) { DbgPrint ("Nbt.DriverEntry[4]: Not loading because of failure to init Dgram MDL Q = <%x>\n", status); CleanupDriverEntry (4); return (status); } //--------------------------------------------------------------------------------------- // // Create the SmbDevice object for Rdr/Srv // if ((NbtConfig.SMBDeviceEnabled) && (!(pNbtSmbDevice = NbtCreateSmbDevice()))) { KdPrint (("Nbt.DriverEntry: Failed to create SmbDevice!\n")); // // Allow the initialization to succeed even if this fails! // } //--------------------------------------------------------------------------------------- // // Create the NBT device object for WINS to use // RtlInitUnicodeString (&ucWinsDeviceBindName, WC_WINS_DEVICE_BIND_NAME); ucWinsDeviceBindName.MaximumLength = sizeof (WC_WINS_DEVICE_BIND_NAME); RtlInitUnicodeString (&ucWinsDeviceExportName, WC_WINS_DEVICE_EXPORT_NAME); ucWinsDeviceExportName.MaximumLength = sizeof (WC_WINS_DEVICE_EXPORT_NAME); // // Try to export a DeviceObject for Wins, but do not add it to the list // of devices which we notify TDI about // Do not care about status because we want to continue even if we fail // status = NbtAllocAndInitDevice (&ucWinsDeviceBindName, &ucWinsDeviceExportName, &pWinsDeviceContext, NBT_DEVICE_WINS); if (!NT_SUCCESS(status)) { DbgPrint ("Nbt.DriverEntry[5]: Not loading because of failure to create pWinsDevContext = <%x>\n", status); CleanupDriverEntry (5); return (status); } status = NbtCreateAdminSecurityDescriptor(&pWinsDeviceContext->DeviceObject); ASSERT(NT_SUCCESS(status)); pWinsDeviceContext->IpAddress = 0; pWinsDeviceContext->DeviceRegistrationHandle = NULL; pWinsDeviceContext->NetAddressRegistrationHandle = NULL; pWinsDeviceContext->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING; //--------------------------------------------------------------------------------------- #ifdef RASAUTODIAL // // Get the automatic connection driver // entry points. // NbtAcdBind(); #endif //--------------------------------------------------------------------------------------- // // Register ourselves as a Provider with Tdi // RtlInitUnicodeString(&ucNetBTProviderName, WC_NETBT_PROVIDER_NAME); ucNetBTProviderName.MaximumLength = sizeof (WC_NETBT_PROVIDER_NAME); status = TdiRegisterProvider (&ucNetBTProviderName, &TdiProviderHandle); if (NT_SUCCESS (status)) { // // Register our Handlers with TDI // RtlInitUnicodeString(&ucNetBTClientName, WC_NETBT_CLIENT_NAME); ucNetBTClientName.MaximumLength = sizeof (WC_NETBT_CLIENT_NAME); RtlZeroMemory(&TdiClientInterface, sizeof(TdiClientInterface)); TdiClientInterface.MajorTdiVersion = MAJOR_TDI_VERSION; TdiClientInterface.MinorTdiVersion = MINOR_TDI_VERSION; TdiClientInterface.ClientName = &ucNetBTClientName; TdiClientInterface.AddAddressHandlerV2 = TdiAddressArrival; TdiClientInterface.DelAddressHandlerV2 = TdiAddressDeletion; TdiClientInterface.BindingHandler = TdiBindHandler; TdiClientInterface.PnPPowerHandler = TdiPnPPowerHandler; status = TdiRegisterPnPHandlers (&TdiClientInterface, sizeof(TdiClientInterface), &TdiClientHandle); if (!NT_SUCCESS (status)) { TdiDeregisterProvider (TdiProviderHandle); TdiProviderHandle = NULL; } } else { TdiProviderHandle = NULL; } if (!NT_SUCCESS (status)) { DbgPrint ("Nbt.DriverEntry[6]: Not loading because of error = <%x>\n", status); CleanupDriverEntry (6); } // // Return to the caller. // return (status); } //---------------------------------------------------------------------------- NTSTATUS NbtDispatchCleanup( IN PDEVICE_OBJECT Device, IN PIRP pIrp ) /*++ Routine Description: This is the NBT driver's dispatch function for IRP_MJ_CLEANUP requests. This function is called when the last reference to the handle is closed. Hence, an NtClose() results in an IRP_MJ_CLEANUP first, and then an IRP_MJ_CLOSE. This function runs down all activity on the object, and when the close comes in the object is actually deleted. Arguments: device - ptr to device object for target device pIrp - ptr to I/O request packet Return Value: STATUS_SUCCESS --*/ { NTSTATUS status; PIO_STACK_LOCATION pIrpSp; tDEVICECONTEXT *pDeviceContext; CTEPagedCode(); pIrpSp = IoGetCurrentIrpStackLocation(pIrp); ASSERT(pIrpSp->MajorFunction == IRP_MJ_CLEANUP); pDeviceContext = (tDEVICECONTEXT *)Device; if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE)) { // IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt.NbtDispatchCleanup: Short-Ckt request --Device=<%x>, Context=<%x>, Context2=<%x>\n", pDeviceContext, pIrpSp->FileObject->FsContext, pIrpSp->FileObject->FsContext2)); status = STATUS_SUCCESS; pIrp->IoStatus.Status = status; IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT); return (status); } // look at the context value that NBT put into the FSContext2 value to // decide what to do switch ((USHORT)pIrpSp->FileObject->FsContext2) { case NBT_ADDRESS_TYPE: // the client is closing the address file, so we must cleanup // and memory blocks associated with it. status = NTCleanUpAddress(pDeviceContext,pIrp); break; case NBT_CONNECTION_TYPE: // the client is closing a connection, so we must clean up any // memory blocks associated with it. status = NTCleanUpConnection(pDeviceContext,pIrp); break; case NBT_WINS_TYPE: // // This is synchronous with the Wins NtClose operation // status = NTCleanUpWinsAddr (pDeviceContext, pIrp); break; case NBT_CONTROL_TYPE: // there is nothing to do here.... status = STATUS_SUCCESS; break; default: /* * complete the i/o successfully. */ status = STATUS_SUCCESS; break; } // // Complete the Irp // ReturnIrp(pIrp, status); NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(status); } // DispatchCleanup //---------------------------------------------------------------------------- NTSTATUS NbtDispatchClose( IN PDEVICE_OBJECT Device, IN PIRP pIrp ) /*++ Routine Description: This is the NBT driver's dispatch function for IRP_MJ_CLOSE requests. This is called after Cleanup (above) is called. Arguments: device - ptr to device object for target device pIrp - ptr to I/O request packet Return Value: an NT status code. --*/ { NTSTATUS status; PIO_STACK_LOCATION pIrpSp; tDEVICECONTEXT *pDeviceContext; CTEPagedCode(); pIrpSp = IoGetCurrentIrpStackLocation(pIrp); ASSERT(pIrpSp->MajorFunction == IRP_MJ_CLOSE); pDeviceContext = (tDEVICECONTEXT *)Device; if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE)) { // IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt.NbtDispatchClose: Short-Ckt request -- Device=<%x>, Context=<%x>, Context2=<%x>\n", pDeviceContext, pIrpSp->FileObject->FsContext, pIrpSp->FileObject->FsContext2)); status = STATUS_SUCCESS; pIrp->IoStatus.Status = status; IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT); return (status); } // // close operations are synchronous. // pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; switch (PtrToUlong(pIrpSp->FileObject->FsContext2)) { case NBT_ADDRESS_TYPE: status = NTCloseAddress(pDeviceContext,pIrp); break; case NBT_CONNECTION_TYPE: status = NTCloseConnection(pDeviceContext,pIrp); break; case NBT_WINS_TYPE: // // We don't need to set the DeviceContext here since we had // already saved it in pWinsInfo // This is an Asynchronous operation wrt the Wins server, hence // we should do only minimal work in this routine -- the // major cleanup should be in the DispatchCleanup routine // status = NTCloseWinsAddr(pDeviceContext,pIrp); break; case NBT_CONTROL_TYPE: // the client is closing the Control Object... // there is nothing to do here.... status = STATUS_SUCCESS; break; default: KdPrint(("Nbt:Close Received for unknown object type = %X\n", pIrpSp->FileObject->FsContext2)); status = STATUS_SUCCESS; break; } // NTCloseAddress can return Pending until the ref count actually gets // to zero. // if (status != STATUS_PENDING) { ReturnIrp(pIrp, status); } NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(status); } // DispatchClose //---------------------------------------------------------------------------- NTSTATUS NbtDispatchCreate( IN PDEVICE_OBJECT Device, IN PIRP pIrp ) /*++ Routine Description: This is the NBT driver's dispatch function for IRP_MJ_CREATE requests. It is called as a consequence of one of the following: a. TdiOpenConnection("\Device\Nbt_Elnkii0"), b. TdiOpenAddress("\Device\Nbt_Elnkii0"), Arguments: Device - ptr to device object being opened pIrp - ptr to I/O request packet pIrp->Status => return status pIrp->MajorFunction => IRP_MD_CREATE pIrp->MinorFunction => not used pIpr->FileObject => ptr to file obj created by I/O system. NBT fills in FsContext pIrp->AssociatedIrp.SystemBuffer => ptr to EA buffer with address of obj to open(Netbios Name) pIrp->Parameters.Create.EaLength => length of buffer specifying the Xport Addr. Return Value: STATUS_SUCCESS or STATUS_PENDING --*/ { NTSTATUS status; PIO_STACK_LOCATION pIrpSp; PFILE_FULL_EA_INFORMATION ea, eabuf; tDEVICECONTEXT *pDeviceContext; UCHAR IrpFlags; tIPADDRESS UNALIGNED *pIpAddressU; tIPADDRESS IpAddress; CTEPagedCode(); pIrpSp = IoGetCurrentIrpStackLocation(pIrp); ASSERT(pIrpSp->MajorFunction == IRP_MJ_CREATE); // // If this device was destroyed, then reject all opens on it. // Ideally we would like the IO sub-system to guarantee that no // requests come down on IoDeleted devices, but..... // pDeviceContext = (tDEVICECONTEXT *)Device; if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE)) { // IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt.NbtDispatchCreate: Short-Ckt request -- Device=<%x>, CtrlCode=<%x>\n", pDeviceContext, pIrpSp->Parameters.DeviceIoControl.IoControlCode)); pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT); return (STATUS_INVALID_DEVICE_STATE); } IrpFlags = pIrpSp->Control; // // set the pending flag here so that it is sure to be set BEFORE the // completion routine gets hit. // pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_PENDING; IoMarkIrpPending(pIrp); /* * was this a TdiOpenConnection() or TdiOpenAddress()? * Get the Extended Attribute pointer and look at the text * value passed in for a match with "TransportAddress" or * "ConnectionContext" (in FindEa) */ ea = (PFILE_FULL_EA_INFORMATION) pIrp->AssociatedIrp.SystemBuffer; IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt.NbtDispatchCreate: Major:Minor=<%x:%x>, PFILE_FULL_EA_INFORMATION = <%x>\n", pIrpSp->MajorFunction, pIrpSp->MinorFunction, ea)); if (!ea) { // a null ea means open the control object status = NTOpenControl(pDeviceContext,pIrp); } else if (eabuf = FindInEA(ea, TdiConnectionContext)) { // not allowed to pass in both a Connect Request and a Transport Address ASSERT(!FindInEA(ea, TdiTransportAddress)); status = NTOpenConnection(pDeviceContext, pIrp, eabuf); } else if (eabuf = FindInEA(ea, TdiTransportAddress)) { status = NTOpenAddr(pDeviceContext, pIrp, eabuf); } else if (eabuf = FindInEA(ea, WINS_INTERFACE_NAME)) { pIpAddressU = (tIPADDRESS UNALIGNED *) &ea->EaName[ea->EaNameLength+1]; if (IpAddress = *pIpAddressU) { status = NTOpenWinsAddr(pDeviceContext, pIrp, IpAddress); } else { status = STATUS_INVALID_ADDRESS; } } else { status = STATUS_INVALID_EA_NAME; } // complete the irp if the status is anything EXCEPT status_pending // since the name query completion routine NTCompletIO completes pending // open addresses if (status != STATUS_PENDING) { #if DBG if (!NT_SUCCESS(status)) { IF_DBG(NBT_DEBUG_NAMESRV) KdPrint(("Nbt.NbtDispatchCreate: Returning Error status = %X\n",status)); } #endif // reset the pending returned bit, since we are NOT returning pending pIrpSp->Control = IrpFlags; ReturnIrp(pIrp,status); } NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(status); } //---------------------------------------------------------------------------- NTSTATUS NbtDispatchDevCtrl( IN PDEVICE_OBJECT Device, IN PIRP pIrp ) /*++ Routine Description: This is the NBT driver's dispatch function for all IRP_MJ_DEVICE_CONTROL requests. Arguments: device - ptr to device object for target device pIrp - ptr to I/O request packet Return Value: NTSTATUS -- Indicates whether the request was successfully queued. --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION pIrpSp; tDEVICECONTEXT *pDeviceContext; ULONG IoControlCode; PULONG_PTR pEntryPoint; pIrpSp = IoGetCurrentIrpStackLocation(pIrp); ASSERT(pIrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL); // // If this device was destroyed, then reject all requests on it. // Ideally we would like the IO sub-system to guarantee that no // requests come down on IoDeleted devices, but..... // pDeviceContext = (tDEVICECONTEXT *)Device; if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE)) { // IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt.NbtDispatchDevCtrl: Short-Ckt request -- Device=<%x>, CtrlCode=<%x>\n", pDeviceContext, pIrpSp->Parameters.DeviceIoControl.IoControlCode)); pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT); return (STATUS_INVALID_DEVICE_STATE); } /* * Initialize the I/O status block. */ pIrp->IoStatus.Status = STATUS_PENDING; pIrp->IoStatus.Information = 0; IoControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode; // Save the IoControl code IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt.NbtDispatchDevCtrl: IoControlCode = <%x>\n", pIrpSp->Parameters.DeviceIoControl.IoControlCode)); /* * if possible, convert the (external) device control into internal * format, then treat it as if it had arrived that way. */ if (STATUS_SUCCESS == TdiMapUserRequest(Device, pIrp, pIrpSp)) { status = NbtDispatchInternalCtrl (Device, pIrp); } #if FAST_DISP // Check if upper layer is querying for fast send path else if (pIrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER) { if (pEntryPoint = pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer) { if (pIrp->RequestorMode != KernelMode) // Bug# 120649: Make sure data + the Address type are good { try { ProbeForWrite (pEntryPoint, sizeof(PVOID *), sizeof(BYTE)); *pEntryPoint = (ULONG_PTR) NTSend; status = STATUS_SUCCESS; } except(EXCEPTION_EXECUTE_HANDLER) { // status = STATUS_UNSUCCESSFUL by default } } else { *pEntryPoint = (ULONG_PTR) NTSend; status = STATUS_SUCCESS; } } IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt.NbtDispatchDevCtrl: direct send handler query %x\n", pEntryPoint)); ReturnIrp(pIrp, status); } #endif else { status = DispatchIoctls (pDeviceContext, pIrp, pIrpSp); } // // Dereference this DeviceContext, unless it was to destroy the Device! // if (IoControlCode != IOCTL_NETBT_DELETE_INTERFACE) { NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); } return (status); } // NbtDispatchDevCtrl //---------------------------------------------------------------------------- NTSTATUS NbtDispatchInternalCtrl( IN PDEVICE_OBJECT Device, IN PIRP pIrp ) /*++ Routine Description: This is the driver's dispatch function for all IRP_MJ_INTERNAL_DEVICE_CONTROL requests. Arguments: device - ptr to device object for target device pIrp - ptr to I/O request packet Return Value: NTSTATUS -- Indicates whether the request was successfully queued. --*/ { tDEVICECONTEXT *pDeviceContext; PIO_STACK_LOCATION pIrpSp; NTSTATUS status; UCHAR IrpFlags; pDeviceContext = (tDEVICECONTEXT *)Device; pIrpSp = IoGetCurrentIrpStackLocation(pIrp); ASSERT(pIrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL); // // this check is first to optimize the Send path // if (pIrpSp->MinorFunction ==TDI_SEND) { // // this routine decides if it should complete the pIrp or not // It never returns status pending, so we can turn off the // pending bit // status = NTSend (pDeviceContext,pIrp); return status; } // // If this device was destroyed, then reject all operations on it. // Ideally we would like the IO sub-system to guarantee that no // requests come down on IoDeleted devices, but..... // if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE)) { // IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt.NbtDispatchInternalCtrl: Short-Ckt request -- Device=<%x>, CtrlCode=<%x>\n", pDeviceContext, pIrpSp->Parameters.DeviceIoControl.IoControlCode)); pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT); return (STATUS_INVALID_DEVICE_STATE); } IrpFlags = pIrpSp->Control; IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt.NbtDispatchInternalCtrl: MajorFunction:MinorFunction = <%x:%x>\n", pIrpSp->MajorFunction, pIrpSp->MinorFunction)); switch (pIrpSp->MinorFunction) { case TDI_ACCEPT: MakePending(pIrp); status = NTAccept(pDeviceContext,pIrp); break; case TDI_ASSOCIATE_ADDRESS: MakePending(pIrp); status = NTAssocAddress(pDeviceContext,pIrp); break; case TDI_DISASSOCIATE_ADDRESS: MakePending(pIrp); status = NTDisAssociateAddress(pDeviceContext,pIrp); break; case TDI_CONNECT: MakePending(pIrp); status = NTConnect(pDeviceContext,pIrp); break; case TDI_DISCONNECT: MakePending(pIrp); status = NTDisconnect(pDeviceContext,pIrp); break; case TDI_LISTEN: status = NTListen(pDeviceContext,pIrp); NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(status); break; case TDI_QUERY_INFORMATION: status = NTQueryInformation(pDeviceContext,pIrp); #if DBG if (!NT_SUCCESS(status)) { IF_DBG(NBT_DEBUG_NAMESRV) KdPrint(("Nbt.NbtDispatchInternalCtrl: Bad status from NTQueryInformation = %x\n",status)); } #endif NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(status); break; case TDI_RECEIVE: status = NTReceive(pDeviceContext,pIrp); NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(status); break; case TDI_RECEIVE_DATAGRAM: status = NTReceiveDatagram(pDeviceContext,pIrp); NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(status); break; case TDI_SEND_DATAGRAM: status = NTSendDatagram(pDeviceContext,pIrp); #if DBG if (!NT_SUCCESS(status)) { IF_DBG(NBT_DEBUG_NAMESRV) KdPrint(("Nbt.NbtDispatchInternalCtrl: Bad status from NTSendDatagram = %x\n",status)); } #endif NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(status); break; case TDI_SET_EVENT_HANDLER: MakePending(pIrp); status = NTSetEventHandler(pDeviceContext,pIrp); break; case TDI_SET_INFORMATION: MakePending(pIrp); status = NTSetInformation(pDeviceContext,pIrp); break; #if DBG // // 0x7f is a request by the redirector to put a "magic bullet" out on // the wire, to trigger the Network General Sniffer. // case 0x7f: KdPrint(("NBT.DispatchInternalCtrl: - 07f minor function code\n")); ReturnIrp(pIrp, STATUS_NOT_SUPPORTED); NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(STATUS_NOT_SUPPORTED); #endif /* DBG */ default: KdPrint(("Nbt.DispatchInternalCtrl: Invalid minor function %X\n", pIrpSp->MinorFunction)); ReturnIrp(pIrp, STATUS_INVALID_DEVICE_REQUEST); NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(STATUS_INVALID_DEVICE_REQUEST); } // if the returned status is pending, then we do not complete the IRP // here since it will be completed elsewhere in the code... // if (status != STATUS_PENDING) { #if DBG // *TODO* for debug... if (!NT_SUCCESS(status)) { IF_DBG(NBT_DEBUG_NAMESRV) KdPrint(("Nbt.NbtDispatchInternalCtrl: Returning Error status = %X,MinorFunc = %X\n", status,pIrpSp->MinorFunction)); // ASSERTMSG("An error Status reported from NBT",0L); } #endif pIrpSp->Control = IrpFlags; ReturnIrp(pIrp,status); } NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return(status); } // NbtDispatchInternalCtrl //---------------------------------------------------------------------------- ULONG CompleteTimerAndWorkerRequests( ) { CTELockHandle OldIrq; tDEVICECONTEXT *pDeviceContext; LIST_ENTRY *pTimerQEntry; tTIMERQENTRY *pTimer; LIST_ENTRY *pWorkerQEntry; NBT_WORK_ITEM_CONTEXT *pContext; PNBT_WORKER_THREAD_ROUTINE pCompletionRoutine; ULONG NumTimerRequests = 0; ULONG NumDelayedRequests = 0; NTSTATUS status; // // First remove any active Device Contexts if they are still present // CTESpinLock(&NbtConfig.JointLock,OldIrq); while (!IsListEmpty(&NbtConfig.DeviceContexts)) { pDeviceContext = CONTAINING_RECORD(NbtConfig.DeviceContexts.Flink, tDEVICECONTEXT, Linkage); NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_FIND_REF, TRUE); CTESpinFree(&NbtConfig.JointLock,OldIrq); NbtDestroyDevice (pDeviceContext, FALSE); // Don't wait since the Worker threads will not fire CTESpinLock(&NbtConfig.JointLock,OldIrq); NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_FIND_REF, TRUE); } CTESpinFree(&NbtConfig.JointLock,OldIrq); if (pNbtSmbDevice) { NbtDestroyDevice (pNbtSmbDevice, FALSE); // Don't wait since the Worker threads will not fire pNbtSmbDevice = NULL; } NbtDestroyDevice (pWinsDeviceContext, FALSE); // Don't wait since the Worker threads will not fire StopInitTimers(); KeClearEvent (&NbtConfig.TimerQLastEvent); // // if any other timers are active, stop them // CTESpinLock(&NbtConfig.JointLock,OldIrq); while (!IsListEmpty(&TimerQ.ActiveHead)) { pTimerQEntry = RemoveHeadList(&TimerQ.ActiveHead); pTimer = CONTAINING_RECORD(pTimerQEntry,tTIMERQENTRY,Linkage); InitializeListHead (&pTimer->Linkage); // in case the Linkage is touched again IF_DBG(NBT_DEBUG_PNP_POWER) KdPrint (("CompleteTimerAndWorkerRequests[%d]: Completing request <%x>\n", NumTimerRequests, pTimer)); StopTimer (pTimer, NULL, NULL); NumTimerRequests++; } // // See if there are any Timers currently executing, and if so, wait for // them to complete // if (NbtConfig.NumTimersRunning) { CTESpinFree(&NbtConfig.JointLock,OldIrq); status = KeWaitForSingleObject(&NbtConfig.TimerQLastEvent, // Object to wait on. Executive, // Reason for waiting KernelMode, // Processor mode FALSE, // Alertable NULL); // Timeout ASSERT(status == STATUS_SUCCESS); } else { CTESpinFree(&NbtConfig.JointLock,OldIrq); } // // See if there are any worker threads currently executing, and if so, wait for // them to complete // KeClearEvent (&NbtConfig.WorkerQLastEvent); CTESpinLock(&NbtConfig.WorkerQLock,OldIrq); if (NbtConfig.NumWorkerThreadsQueued) { CTESpinFree(&NbtConfig.WorkerQLock,OldIrq); status = KeWaitForSingleObject(&NbtConfig.WorkerQLastEvent, // Object to wait on. Executive, // Reason for waiting KernelMode, // Processor mode FALSE, // Alertable NULL); // Timeout ASSERT(status == STATUS_SUCCESS); } else { CTESpinFree(&NbtConfig.WorkerQLock,OldIrq); } // // Dequeue each of the requests in the Worker Queue and complete them // CTESpinLock(&NbtConfig.WorkerQLock,OldIrq); while (!IsListEmpty(&NbtConfig.WorkerQList)) { pWorkerQEntry = RemoveHeadList(&NbtConfig.WorkerQList); pContext = CONTAINING_RECORD(pWorkerQEntry, NBT_WORK_ITEM_CONTEXT, NbtConfigLinkage); CTESpinFree(&NbtConfig.WorkerQLock,OldIrq); // To get back to non-raised Irql! pCompletionRoutine = pContext->WorkerRoutine; IF_DBG(NBT_DEBUG_PNP_POWER) KdPrint (("CompleteTimerAndWorkerRequests[%d]: Completing request <%x>\n", NumDelayedRequests, pCompletionRoutine)); (*pCompletionRoutine) (pContext->pTracker, pContext->pClientContext, pContext->ClientCompletion, pContext->pDeviceContext); CTEMemFree ((PVOID) pContext); NumDelayedRequests++; // // Acquire Lock again to check if we have completed all the requests // CTESpinLock(&NbtConfig.WorkerQLock,OldIrq); } CTESpinFree(&NbtConfig.WorkerQLock,OldIrq); // // Now destroy the Devices queued on the Free'ed list since there are no more Worker threads or // Timers pending! // while (!IsListEmpty(&NbtConfig.DevicesAwaitingDeletion)) { pDeviceContext = CONTAINING_RECORD(NbtConfig.DevicesAwaitingDeletion.Flink, tDEVICECONTEXT, Linkage); ASSERT (pDeviceContext->RefCount == 0); KdPrint(("Nbt.CompleteTimerAndWorkerRequests: *** Destroying Device *** \n\t%wZ\n", &pDeviceContext->ExportName)); RemoveEntryList (&pDeviceContext->Linkage); // Remove the Device from the to-be-free'ed list CTEMemFree (pDeviceContext->ExportName.Buffer); IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext); } ASSERT (IsListEmpty(&NbtConfig.AddressHead)); KdPrint(("Nbt.CompleteTimerAndWorkerRequests: Completed <%d> Timer and <%d> Delayed requests\n", NumTimerRequests, NumDelayedRequests)); return (NumTimerRequests + NumDelayedRequests); } //---------------------------------------------------------------------------- VOID NbtUnload( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: This is the NBT driver's dispatch function for Unload requests Arguments: DriverObject - Pointer to driver object created by the system. Return Value: None --*/ { NTSTATUS status; CTEPagedCode(); KdPrint(("Nbt.NbtUnload: Unloading ...\n")); // // After setting the following flag, no new requests should be queued on to // the WorkerQ NbtConfig.WorkerQLastEvent will be set when all the current // requests have finished executing // NbtConfig.Unloading = TRUE; // // Unbind fron the RAS driver if we were bound // NbtAcdUnbind (); status = TdiDeregisterPnPHandlers(TdiClientHandle); IF_DBG(NBT_DEBUG_PNP_POWER) KdPrint (("NbtUnload: TdiDeregisterPnPHandlers returned <%x>\n", status)); status = TdiDeregisterProvider (TdiProviderHandle); IF_DBG(NBT_DEBUG_PNP_POWER) KdPrint (("NbtUnload: TdiDeregisterProvider returned <%x>\n", status)); // // Dequeue each of the requests in the Timer and NbtConfigWorker Queues and complete them // CompleteTimerAndWorkerRequests(); // // Now cleanup the rest of the static allocations // CleanupDriverEntry (5); ASSERT (IsListEmpty (&NbtConfig.PendingNameQueries)); if (NbtConfig.pServerBindings) { CTEFreeMem (NbtConfig.pServerBindings); NbtConfig.pServerBindings = NULL; } if (NbtConfig.pClientBindings) { CTEFreeMem (NbtConfig.pClientBindings); NbtConfig.pClientBindings = NULL; } #ifdef _NBT_WMI_SOFTWARE_TRACING_ WPP_CLEANUP(DriverObject); #endif } //---------------------------------------------------------------------------- NTSTATUS NbtDispatchPnP( IN PDEVICE_OBJECT Device, IN PIRP pIrp ) { tDEVICECONTEXT *pDeviceContext; PIO_STACK_LOCATION pIrpSp, pIrpSpNext; NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; tCONNECTELE *pConnectEle; tLOWERCONNECTION *pLowerConn; KIRQL OldIrq1, OldIrq2; PDEVICE_OBJECT pTcpDeviceObject; PFILE_OBJECT pTcpFileObject; tFILE_OBJECTS *pFileObjectsContext; pIrpSp = IoGetCurrentIrpStackLocation(pIrp); // // If this device was destroyed, then reject all operations on it. // Ideally we would like the IO sub-system to guarantee that no // requests come down on IoDeleted devices, but..... // pDeviceContext = (tDEVICECONTEXT *)Device; if (!NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE)) { IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt.NbtDispatchPnP: Short-Ckt request -- Device=<%x>\n", pDeviceContext)); pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT); return (STATUS_INVALID_DEVICE_STATE); } switch (pIrpSp->MinorFunction) { case IRP_MN_QUERY_DEVICE_RELATIONS: { if (pIrpSp->Parameters.QueryDeviceRelations.Type==TargetDeviceRelation) { if (PtrToUlong(pIrpSp->FileObject->FsContext2) == NBT_CONNECTION_TYPE) { // pass to transport to get the PDO // pConnectEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext; if (NBT_VERIFY_HANDLE2 (pConnectEle, NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN)) { CTESpinLock(pConnectEle, OldIrq1); pLowerConn = (tLOWERCONNECTION *)pConnectEle->pLowerConnId; if (NBT_VERIFY_HANDLE (pLowerConn, NBT_VERIFY_LOWERCONN)) { CTESpinLock(pLowerConn, OldIrq2); NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_QUERY_DEVICE_REL); CTESpinFree(pLowerConn, OldIrq2); CTESpinFree(pConnectEle, OldIrq1); if ((pTcpFileObject = pLowerConn->pFileObject) && (pTcpDeviceObject = IoGetRelatedDeviceObject (pLowerConn->pFileObject))) { // // Simply pass the Irp on by to the Transport, and let it // fill in the info // pIrpSpNext = IoGetNextIrpStackLocation (pIrp); *pIrpSpNext = *pIrpSp; IoSetCompletionRoutine (pIrp, NULL, NULL, FALSE, FALSE, FALSE); pIrpSpNext->FileObject = pTcpFileObject; pIrpSpNext->DeviceObject = pTcpDeviceObject; status = IoCallDriver(pTcpDeviceObject, pIrp); NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return status; } else { status = STATUS_INVALID_HANDLE; } NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_QUERY_DEVICE_REL, FALSE); } else { status = STATUS_CONNECTION_INVALID; CTESpinFree(pConnectEle, OldIrq1); } } else { status = STATUS_INVALID_HANDLE; } } else if ( PtrToUlong(pIrpSp->FileObject->FsContext2) == NBT_ADDRESS_TYPE) { CTESpinLock(&NbtConfig.JointLock,OldIrq1); if ((pDeviceContext->IpAddress) && (pFileObjectsContext = pDeviceContext->pFileObjects) && (pTcpFileObject = pFileObjectsContext->pDgramFileObject) && (pTcpDeviceObject = pFileObjectsContext->pDgramDeviceObject)) { pFileObjectsContext->RefCount++; // Dereferenced after the Query has completed // // pass the Irp to transport to get the PDO // pIrpSpNext = IoGetNextIrpStackLocation (pIrp); *pIrpSpNext = *pIrpSp; IoSetCompletionRoutine (pIrp, NULL, NULL, FALSE, FALSE, FALSE); pIrpSpNext->FileObject = pTcpFileObject; pIrpSpNext->DeviceObject = pTcpDeviceObject; CTESpinFree(&NbtConfig.JointLock,OldIrq1); status = IoCallDriver(pTcpDeviceObject, pIrp); CTESpinLock(&NbtConfig.JointLock,OldIrq1); if (--pFileObjectsContext->RefCount == 0) { CTEQueueForNonDispProcessing(DelayedNbtCloseFileHandles, NULL, pFileObjectsContext, NULL, NULL, TRUE); } NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, TRUE); CTESpinFree(&NbtConfig.JointLock,OldIrq1); return status; } else { CTESpinFree(&NbtConfig.JointLock,OldIrq1); status = STATUS_INVALID_DEVICE_REQUEST; } } else { ASSERT (0); } } break; } default: { break; } } ReturnIrp(pIrp, status); NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_DISPATCH, FALSE); return status; } //---------------------------------------------------------------------------- PFILE_FULL_EA_INFORMATION FindInEA( IN PFILE_FULL_EA_INFORMATION start, IN PCHAR wanted ) /*++ Routine Description: This function check for the "Wanted" string in the Ea structure and returns a pointer to the extended attribute structure representing the given extended attribute name. Arguments: device - ptr to device object for target device pIrp - ptr to I/O request packet Return Value: pointer to the extended attribute structure, or NULL if not found. --*/ { PFILE_FULL_EA_INFORMATION eabuf; CTEPagedCode(); // // Bug # 225668: advance eabug ptr by typecasting it to UCHAR // for (eabuf = start; eabuf; eabuf = (PFILE_FULL_EA_INFORMATION) ((PUCHAR)eabuf + eabuf->NextEntryOffset)) { if (strncmp(eabuf->EaName,wanted,eabuf->EaNameLength) == 0) { return eabuf; } if (eabuf->NextEntryOffset == 0) { return((PFILE_FULL_EA_INFORMATION) NULL); } } return((PFILE_FULL_EA_INFORMATION) NULL); } // FindEA //---------------------------------------------------------------------------- VOID ReturnIrp( IN PIRP pIrp, IN int status ) /*++ Routine Description: This function completes an IRP, and arranges for return parameters, if any, to be copied. Although somewhat a misnomer, this function is named after a similar function in the SpiderSTREAMS emulator. Arguments: pIrp - pointer to the IRP to complete status - completion status of the IRP Return Value: number of bytes copied back to the user. --*/ { KIRQL oldlevel; CCHAR priboost; // // pIrp->IoStatus.Information is meaningful only for STATUS_SUCCESS // // set the Irps cancel routine to null or the system may bugcheck // with a bug code of CANCEL_STATE_IN_COMPLETED_IRP // // refer to IoCancelIrp() ..\ntos\io\iosubs.c // IoAcquireCancelSpinLock(&oldlevel); IoSetCancelRoutine(pIrp,NULL); IoReleaseCancelSpinLock(oldlevel); pIrp->IoStatus.Status = status; priboost = (CCHAR) ((status == STATUS_SUCCESS) ? IO_NETWORK_INCREMENT : IO_NO_INCREMENT); IoCompleteRequest(pIrp, priboost); return; } //---------------------------------------------------------------------------- VOID MakePending( IN PIRP pIrp ) /*++ Routine Description: This function marks an irp pending and sets the correct status. Arguments: pIrp - pointer to the IRP to complete status - completion status of the IRP Return Value: --*/ { IoMarkIrpPending(pIrp); pIrp->IoStatus.Status = STATUS_PENDING; pIrp->IoStatus.Information = 0; } #ifdef _NBT_WMI_SOFTWARE_TRACING_ int nbtlog_strnlen(char *p, int n) { int i; for (i = 0; (i < n) && *p; i++, p++) { } return i; } #endif