/*++ 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 "nbtprocs.h" #include #if DBG // allocate storage for the global debug flag NbtDebug #ifdef _PNP_POWER ULONG NbtDebug=NBT_DEBUG_PNP_POWER; // NT PNP debugging #else // _PNP_POWER ULONG NbtDebug=0x00000000; // disable all debugging #endif // _PNP_POWER #endif // DBG NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); NTSTATUS NbtDispatchCleanup( IN PDEVICE_OBJECT Device, IN PIRP irp ); NTSTATUS NbtDispatchClose( IN PDEVICE_OBJECT device, IN PIRP irp ); NTSTATUS NbtDispatchCreate( IN PDEVICE_OBJECT Device, IN PIRP pIrp ); NTSTATUS NbtDispatchDevCtrl( IN PDEVICE_OBJECT device, IN PIRP irp ); NTSTATUS NbtDispatchInternalCtrl( IN PDEVICE_OBJECT device, IN PIRP irp ); PFILE_FULL_EA_INFORMATION FindInEA( IN PFILE_FULL_EA_INFORMATION start, IN PCHAR wanted ); VOID ReturnIrp( IN PIRP irp, IN int status ); VOID MakePending( IN PIRP pIrp ); #ifdef RASAUTODIAL VOID NbtAcdBind(); #endif // RASAUTODIAL //******************* Pageable Routine Declarations **************** #ifdef ALLOC_PRAGMA #pragma CTEMakePageable(INIT, DriverEntry) #ifdef RASAUTODIAL #pragma CTEMakePageable(INIT, NbtAcdBind) #endif // RASAUTODIAL #pragma CTEMakePageable(PAGE, NbtDispatchCleanup) #pragma CTEMakePageable(PAGE, NbtDispatchClose) #pragma CTEMakePageable(PAGE, NbtDispatchCreate) #pragma CTEMakePageable(PAGE, NbtDispatchDevCtrl) #pragma CTEMakePageable(PAGE, FindInEA) #endif //******************* Pageable Routine Declarations **************** //---------------------------------------------------------------------------- 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; tADDRARRAY *pAddr; tDEVICES *pBindDevices=NULL; tDEVICES *pExportDevices=NULL; tADDRARRAY *pAddrArray=NULL; #ifndef _PNP_LATER int i; PLIST_ENTRY pHead; PLIST_ENTRY pEntry; NTSTATUS Locstatus; tDEVICECONTEXT *pDeviceContext; ULONG DevicesStarted; #endif // _PNP_POWER CTEPagedCode(); #ifdef _PNP_POWER TdiInitialize(); #endif // // get the file system process for NBT since we need to know this for // allocating and freeing handles // NbtFspProcess =(PEPROCESS)PsGetCurrentProcess(); // // read in registry configuration data // status = NbtReadRegistry(RegistryPath, DriverObject, &NbtConfig, &pBindDevices, &pExportDevices, &pAddrArray); if (!NT_SUCCESS(status)) { KdPrint(("NBT:Fatal Error - Failed registry read! status = %X\n", status)); return(status); } // // Initialize NBT global data. // status = InitNotOs() ; if (!NT_SUCCESS(status)) { NbtLogEvent(EVENT_NBT_NON_OS_INIT,status); KdPrint(("NBT:OS Independent initialization failed! status = %X\n", status)); return(status); } // // 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->DriverUnload = NULL; #ifndef _PNP_LATER // start some timers status = InitTimersNotOs(); if (!NT_SUCCESS(status)) { NbtLogEvent(EVENT_NBT_TIMERS,status); KdPrint(("NBT:Failed to Initialize the Timers!,status = %X\n", status)); StopInitTimers(); return(status); } // #else // _PNP_POWER // ASSERT (status == STATUS_SUCCESS); NbtConfig.uDevicesStarted = 0; #endif // _PNP_POWER pNbtGlobConfig->iBufferSize[eNBT_FREE_SESSION_MDLS] = sizeof(tSESSIONHDR); pNbtGlobConfig->iBufferSize[eNBT_DGRAM_MDLS] = DGRAM_HDR_SIZE + (pNbtGlobConfig->ScopeLength << 1); // create some MDLs, for session sends to speed up the sends. status = NbtInitMdlQ( &NbtConfig.SessionMdlFreeSingleList, eNBT_FREE_SESSION_MDLS); if (!NT_SUCCESS(status)) { KdPrint(("NBT:Failed to Initialize the Session MDL Queue!,status = %X\n", status)); return(status); } // create some MDLs for datagram sends status = NbtInitMdlQ( &NbtConfig.DgramMdlFreeSingleList, eNBT_DGRAM_MDLS); if (!NT_SUCCESS(status)) { KdPrint(("NBT:Failed to Initialize the Dgram MDL Queue!,status = %X\n", status)); return(status); } #ifndef _PNP_LATER // // Create the NBT device object for each adapter configured // pAddr = pAddrArray; DevicesStarted = 0; for (i=0; iuNumDevices; i++ ) { // this call ultimately allocates storage for the returned NameString // that holds the Ipaddress status = NbtCreateDeviceObject( DriverObject, pNbtGlobConfig, &pBindDevices->Names[i], &pExportDevices->Names[i], pAddr, RegistryPath, #ifndef _IO_DELETE_DEVICE_SUPPORTED FALSE, #endif &pDeviceContext); // for a Bnode there are no Wins server addresses, so this Ptr can // be null. if (pAddr) { pAddr++; } // // allow not having an address to succeed - DHCP will // provide an address later // if (pDeviceContext != NULL) { if (status == STATUS_INVALID_ADDRESS) { // // set to null so we know not to allow connections or dgram // sends on this adapter // pDeviceContext->IpAddress = 0; DevicesStarted++; status = STATUS_SUCCESS; } if ((NT_SUCCESS(status)) || (status == STATUS_INVALID_ADDRESS_COMPONENT)) { status = STATUS_SUCCESS; NbtConfig.uDevicesStarted++; } { // // We can tolerate the invalid address component failure since IP does not know of // static addresses at this time. // if (!NT_SUCCESS(status)) { pDeviceContext->RegistrationHandle = NULL; KdPrint((" Create Device Object Failed with status= %X, num devices = %X\n",status, NbtConfig.uNumDevices)); NbtLogEvent(EVENT_NBT_CREATE_DEVICE,status); // // this device will not be started so decrement the count of started // ones. // NbtConfig.AdapterCount--; // // cleanup the mess and free the device object since we had some // sort of failure. // pHead = &NbtConfig.DeviceContexts; pEntry = RemoveTailList(pHead); ASSERT (pDeviceContext == CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage)); if (pDeviceContext->hNameServer) { ObDereferenceObject(pDeviceContext->pNameServerFileObject); Locstatus = NTZwCloseFile(pDeviceContext->hNameServer); KdPrint(("Close NameSrv File status = %X\n",Locstatus)); } if (pDeviceContext->hDgram) { ObDereferenceObject(pDeviceContext->pDgramFileObject); Locstatus = NTZwCloseFile(pDeviceContext->hDgram); KdPrint(("Close Dgram File status = %X\n",Locstatus)); } if (pDeviceContext->hSession) { ObDereferenceObject(pDeviceContext->pSessionFileObject); Locstatus = NTZwCloseFile(pDeviceContext->hSession); KdPrint(("Close Session File status = %X\n",Locstatus)); } if (pDeviceContext->hControl) { ObDereferenceObject(pDeviceContext->pControlFileObject); Locstatus = NTZwCloseFile(pDeviceContext->hControl); KdPrint(("Close Control File status = %X\n",Locstatus)); } IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext); } else { // // So we know that we need to register this device when an IP addres // appears // pDeviceContext->RegistrationHandle = NULL; DevicesStarted++; pDeviceContext->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING; } } } } // // if no devices were created, then stop the timers and free the resources // if (DevicesStarted == 0) { ExDeleteResource(&NbtConfig.Resource); StopInitTimers(); } else { // // at least one device context was created successfully, so return success // status = STATUS_SUCCESS; } if (NbtConfig.uNumDevices == 0) { NbtLogEvent(EVENT_NBT_NO_DEVICES,0); } #endif // _PNP_POWER if (pBindDevices) { CTEMemFree((PVOID)pBindDevices->RegistrySpace); CTEMemFree((PVOID)pBindDevices); } if (pExportDevices) { CTEMemFree((PVOID)pExportDevices->RegistrySpace); CTEMemFree((PVOID)pExportDevices); } if (pAddrArray) { CTEMemFree((PVOID)pAddrArray); } #ifndef _PNP_LATER // // Get an Irp for the out of resource queue (used to disconnect sessions // when really low on memory) // if (!IsListEmpty(&NbtConfig.DeviceContexts)) { pEntry = NbtConfig.DeviceContexts.Flink; pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage); NbtConfig.OutOfRsrc.pIrp = NTAllocateNbtIrp(&pDeviceContext->DeviceObject); if (!NbtConfig.OutOfRsrc.pIrp) { status = STATUS_INSUFFICIENT_RESOURCES; } else { // // allocate a dpc structure and keep it: we might need if we hit an // out-of-resource condition // NbtConfig.OutOfRsrc.pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('a')); if (!NbtConfig.OutOfRsrc.pDpc) { IoFreeIrp(NbtConfig.OutOfRsrc.pIrp); status = STATUS_INSUFFICIENT_RESOURCES; } } #ifdef RASAUTODIAL // // Get the automatic connection driver // entry points. // if (status == STATUS_SUCCESS) { NbtAcdBind(); } #endif #ifdef _PNP_POWER (void)TdiRegisterAddressChangeHandler( AddressArrival, AddressDeletion, &AddressChangeHandle ); #ifdef WATCHBIND (void)TdiRegisterNotificationHandler( BindHandler, UnbindHandler, &BindingHandle ); #endif // WATCHBIND #endif // _PNP_POWER } else { KdPrint(("NetBT!DriverEntry: Huh? Started NetBT with no devices!")); } #endif // _PNP_POWER NbtConfig.InterfaceIndex = 0; // // Return to the caller. // return(status); } //---------------------------------------------------------------------------- NTSTATUS NbtDispatchCleanup( IN PDEVICE_OBJECT Device, IN PIRP irp ) /*++ 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 irp - ptr to I/O request packet Return Value: STATUS_SUCCESS --*/ { NTSTATUS status; PIO_STACK_LOCATION irpsp; tDEVICECONTEXT *pDeviceContext; CTEPagedCode(); pDeviceContext = (tDEVICECONTEXT *)Device; irpsp = IoGetCurrentIrpStackLocation(irp); // check that we got the correct major function code ASSERT(irpsp->MajorFunction == IRP_MJ_CLEANUP); // look at the context value that NBT put into the FSContext2 value to // decide what to do switch ((USHORT)irpsp->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,irp); 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,irp); 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(irp, status); 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 irpsp; tDEVICECONTEXT *pDeviceContext; CTEPagedCode(); pDeviceContext = (tDEVICECONTEXT *)Device; // // close operations are synchronous. // pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; irpsp = IoGetCurrentIrpStackLocation(pIrp); ASSERT(irpsp->MajorFunction == IRP_MJ_CLOSE); switch ((ULONG)irpsp->FileObject->FsContext2) { case NBT_ADDRESS_TYPE: status = NTCloseAddress(pDeviceContext,pIrp); break; case NBT_CONNECTION_TYPE: status = NTCloseConnection(pDeviceContext,pIrp); break; case NBT_WINS_TYPE: 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", irpsp->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); } 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; tDEVICECONTEXT *pDeviceContext; UCHAR IrpFlags; CTEPagedCode(); pDeviceContext = (tDEVICECONTEXT *)Device; // // 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..... // if (InterlockedExchangeAdd(&pDeviceContext->IsDestroyed, 0) != 0) { // IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt Rejecting Create minor Func\n")); pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT); return STATUS_INVALID_DEVICE_STATE; } pIrpsp = IoGetCurrentIrpStackLocation(pIrp); ASSERT(pIrpsp->MajorFunction == IRP_MJ_CREATE); 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); IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt Internal Ctrl minor Func = %X\n",pIrpsp->MinorFunction)); /* * 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 (!ea) { // a null ea means open the control object status = NTOpenControl(pDeviceContext,pIrp); } else if (FindInEA(ea, TdiConnectionContext)) { // not allowed to pass in both a Connect Request and a Transport Address ASSERT(!FindInEA(ea, TdiTransportAddress)); status = NTOpenConnection(pDeviceContext,pIrp); } else if (FindInEA(ea, TdiTransportAddress)) { status = NTOpenAddr(pDeviceContext,pIrp); } else if (FindInEA(ea, WINS_INTERFACE_NAME)) { status = NTOpenWinsAddr(pDeviceContext,pIrp); } else { status = STATUS_INVALID_EA_NAME; pIrpsp->Control = IrpFlags; ReturnIrp(pIrp, status); return(status); } // 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 // *TODO* for debug... if (!NT_SUCCESS(status)) { IF_DBG(NBT_DEBUG_NAMESRV) KdPrint(("Nbt: error return status = %X\n",status)); //ASSERTMSG("An error Status reported from NBT",0L); } #endif // reset the pending returned bit, since we are NOT returning pending pIrpsp->Control = IrpFlags; ReturnIrp(pIrp,status); } return(status); } //---------------------------------------------------------------------------- NTSTATUS NbtDispatchDevCtrl( IN PDEVICE_OBJECT Device, IN PIRP irp ) /*++ 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 irp - ptr to I/O request packet Return Value: NTSTATUS -- Indicates whether the request was successfully queued. --*/ { NTSTATUS status; PIO_STACK_LOCATION irpsp; tDEVICECONTEXT *pDeviceContext; CTEPagedCode(); pDeviceContext = (tDEVICECONTEXT *)Device; irpsp = IoGetCurrentIrpStackLocation(irp); // // 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..... // if (InterlockedExchangeAdd(&pDeviceContext->IsDestroyed, 0) != 0) { // IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt Rejecting Dev Ctrl code = %X\n",irpsp->Parameters.DeviceIoControl.IoControlCode)); irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; IoCompleteRequest (irp, IO_NETWORK_INCREMENT); return STATUS_INVALID_DEVICE_STATE; } /* * Initialize the I/O status block. */ irp->IoStatus.Status = STATUS_PENDING; irp->IoStatus.Information = 0; ASSERT(irpsp->MajorFunction == IRP_MJ_DEVICE_CONTROL); IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt:DevCtrl hit with ControlCode == %X\n", irpsp->Parameters.DeviceIoControl.IoControlCode)); if ((irpsp->Parameters.DeviceIoControl.IoControlCode >= IOCTL_NETBT_PURGE_CACHE) && (irpsp->Parameters.DeviceIoControl.IoControlCode IsDestroyed, 0) != 0) { // IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt Rejecting Internal minor fn. = %X\n",pIrpsp->MinorFunction)); pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT); return STATUS_INVALID_DEVICE_STATE; } /* * Initialize the I/O status block. */ // // this check if first to optimize the Send path // if (pIrpsp->MinorFunction ==TDI_SEND) { // // this routine decides if it should complete the irp or not // It never returns status pending, so we can turn off the // pending bit // return( NTSend(pDeviceContext,pIrp) ); } IrpFlags = pIrpsp->Control; ASSERT(pIrpsp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL); IF_DBG(NBT_DEBUG_DRIVER) KdPrint(("Nbt Internal Ctrl minor Func = %X\n",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); return(status); break; case TDI_QUERY_INFORMATION: status = NTQueryInformation(pDeviceContext,pIrp); #if DBG if (!NT_SUCCESS(status)) { IF_DBG(NBT_DEBUG_NAMESRV) KdPrint(("Nbt: Bad status from Query Info = %X\n",status)); } #endif return(status); break; case TDI_RECEIVE: status = NTReceive(pDeviceContext,pIrp); return(status); break; case TDI_RECEIVE_DATAGRAM: status = NTReceiveDatagram(pDeviceContext,pIrp); return(status); break; case TDI_SEND_DATAGRAM: status = NTSendDatagram(pDeviceContext,pIrp); #if DBG if (!NT_SUCCESS(status)) { IF_DBG(NBT_DEBUG_NAMESRV) KdPrint(("Nbt: Bad status from Dgram Send = %X\n",status)); } #endif 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); return(STATUS_NOT_SUPPORTED); #endif /* DBG */ default: KdPrint(("NBT:Dispatch Internal Ctl - invalid minor function %X\n", pIrpsp->MinorFunction)); ReturnIrp(pIrp, STATUS_INVALID_DEVICE_REQUEST); 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:error return status = %X,MinorFunc = %X\n",status,pIrpsp->MinorFunction)); // ASSERTMSG("An error Status reported from NBT",0L); } #endif pIrpsp->Control = IrpFlags; ReturnIrp(pIrp,status); } return(status); } // NbtDispatchInternalCtrl //---------------------------------------------------------------------------- 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(); for (eabuf = start; eabuf; 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; }