You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
645 lines
19 KiB
645 lines
19 KiB
/*++
|
|
|
|
Copyright (c) 1989-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dns.c
|
|
|
|
Abstract:
|
|
|
|
This module implements a simple DNSv6 resolver
|
|
|
|
Author:
|
|
|
|
Jiandong Ruan
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "dns.tmh"
|
|
|
|
VOID
|
|
SmbDnsTimeout(
|
|
PKDPC Dpc,
|
|
PSMB_GETHOST_CONTEXT Context,
|
|
PVOID Unused1,
|
|
PVOID Unused2
|
|
);
|
|
|
|
PIRP __inline
|
|
SmbDnsPopResolver(
|
|
VOID
|
|
)
|
|
{
|
|
PIRP Irp;
|
|
|
|
ASSERT(Dns.ResolverNumber >= 0);
|
|
if (Dns.ResolverNumber <= 0) {
|
|
return NULL;
|
|
}
|
|
|
|
Dns.ResolverNumber--;
|
|
Irp = Dns.ResolverList[Dns.ResolverNumber];
|
|
Dns.ResolverList[Dns.ResolverNumber] = NULL;
|
|
|
|
SmbTrace(SMB_TRACE_DNS, ("remove DNS Irp %p, # of resolvers=%d", Irp, Dns.ResolverNumber));
|
|
SmbPrint(SMB_TRACE_DNS, ("remove DNS Irp %p, # of resolvers=%d\n", Irp, Dns.ResolverNumber));
|
|
ASSERT(Irp != NULL);
|
|
return Irp;
|
|
}
|
|
|
|
NTSTATUS __inline
|
|
SmbDnsPushResolver(
|
|
PIRP Irp
|
|
)
|
|
{
|
|
ASSERT(SmbCfg.DnsMaxResolver >= 1 && SmbCfg.DnsMaxResolver <= DNS_MAX_RESOLVER);
|
|
|
|
if (Dns.ResolverNumber >= SmbCfg.DnsMaxResolver) {
|
|
return STATUS_QUOTA_EXCEEDED;
|
|
}
|
|
|
|
ASSERT(IsListEmpty(&Dns.WaitingServerList));
|
|
IoMarkIrpPending(Irp);
|
|
Dns.ResolverList[Dns.ResolverNumber] = Irp;
|
|
Dns.ResolverNumber++;
|
|
|
|
SmbTrace(SMB_TRACE_DNS, ("queue DNS Irp %p, # of resolvers=%d", Irp, Dns.ResolverNumber));
|
|
SmbPrint(SMB_TRACE_DNS, ("queue DNS Irp %p, # of resolvers=%d\n", Irp, Dns.ResolverNumber));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbInitDnsResolver(
|
|
VOID
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
RtlZeroMemory(&Dns, sizeof(Dns));
|
|
|
|
KeInitializeSpinLock(&Dns.Lock);
|
|
InitializeListHead(&Dns.WaitingServerList);
|
|
InitializeListHead(&Dns.BeingServedList);
|
|
Dns.NextId = 1;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
SmbShutdownDnsResolver(
|
|
VOID
|
|
)
|
|
{
|
|
LONG i;
|
|
PIRP Irp;
|
|
KIRQL Irql;
|
|
|
|
SMB_ACQUIRE_SPINLOCK(&Dns, Irql);
|
|
while (Irp = SmbDnsPopResolver()) {
|
|
SMB_RELEASE_SPINLOCK_DPC(&Dns);
|
|
Irp->IoStatus.Status = STATUS_SYSTEM_SHUTDOWN;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
SMB_ACQUIRE_SPINLOCK_DPC(&Dns);
|
|
}
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
}
|
|
|
|
VOID
|
|
SmbPassupDnsRequest(
|
|
IN PUNICODE_STRING Name,
|
|
IN PSMB_GETHOST_CONTEXT Context,
|
|
IN PIRP DnsIrp,
|
|
IN KIRQL Irql
|
|
)
|
|
{
|
|
PSMB_DNS_BUFFER DnsBuffer;
|
|
|
|
//
|
|
// Spinlock should be held
|
|
//
|
|
ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
|
|
|
|
InsertTailList(&Dns.BeingServedList, &Context->Linkage);
|
|
DnsBuffer = (PSMB_DNS_BUFFER)MmGetSystemAddressForMdlSafe(DnsIrp->MdlAddress, HighPagePriority);
|
|
ASSERT(DnsBuffer);
|
|
Context->Id = DnsBuffer->Id = Dns.NextId++;
|
|
|
|
if (0 == Dns.NextId) {
|
|
Dns.NextId = 1;
|
|
}
|
|
SmbTrace(SMB_TRACE_DNS, ("pass up DNS request: Irp %p, # of resolvers=%d", DnsIrp, Dns.ResolverNumber));
|
|
SmbPrint(SMB_TRACE_DNS, ("pass up DNS request: Irp %p, # of resolvers=%d\n", DnsIrp, Dns.ResolverNumber));
|
|
|
|
ASSERT(Name->Length <= sizeof(DnsBuffer->Name));
|
|
RtlCopyMemory(DnsBuffer->Name, Name->Buffer, Name->Length);
|
|
DnsBuffer->Name[Name->Length/sizeof(WCHAR)] = L'\0';
|
|
DnsBuffer->NameLen = (Name->Length/sizeof(WCHAR)) + 1;
|
|
DnsBuffer->Resolved = FALSE;
|
|
DnsBuffer->IpAddrsNum = 0;
|
|
DnsBuffer->RequestType = 0;
|
|
if (SmbCfg.Tcp6Available) {
|
|
DnsBuffer->RequestType |= SMB_DNS_AAAA;
|
|
if (SmbCfg.bIPv6EnableOutboundGlobal) {
|
|
DnsBuffer->RequestType |= SMB_DNS_AAAA_GLOBAL;
|
|
}
|
|
}
|
|
if (SmbCfg.Tcp4Available) {
|
|
DnsBuffer->RequestType |= SMB_DNS_A;
|
|
}
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
|
|
DnsIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
DnsIrp->IoStatus.Information = sizeof(DnsBuffer[0]);
|
|
IoCompleteRequest(DnsIrp, IO_NETWORK_INCREMENT);
|
|
}
|
|
|
|
VOID
|
|
SmbCancelConnectAtDns(
|
|
IN PDEVICE_OBJECT Device,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
BOOL
|
|
LookupLocalName(
|
|
IN PUNICODE_STRING Name,
|
|
IN PSMB_IP_ADDRESS ipaddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Lookup the name in local client list. If it is found,
|
|
return a loopback IP address in ipaddr.
|
|
|
|
TO BE FINISHED.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
TRUE if it is found
|
|
|
|
--*/
|
|
{
|
|
OEM_STRING oemName;
|
|
CHAR NbName[NETBIOS_NAME_SIZE+1];
|
|
KIRQL Irql;
|
|
NTSTATUS status;
|
|
PLIST_ENTRY entry;
|
|
PSMB_CLIENT_ELEMENT client;
|
|
BOOL found = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Name->Length > NETBIOS_NAME_SIZE * sizeof(WCHAR)) {
|
|
return FALSE;
|
|
}
|
|
|
|
oemName.Buffer = NbName;
|
|
oemName.MaximumLength = NETBIOS_NAME_SIZE + 1;
|
|
status = RtlUpcaseUnicodeStringToOemString(&oemName, Name, FALSE);
|
|
if (!NT_SUCCESS(status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (oemName.Length > NETBIOS_NAME_SIZE) {
|
|
return FALSE;
|
|
}
|
|
|
|
ASSERT(oemName.Buffer == NbName);
|
|
//
|
|
// Pad the name with SPACEs
|
|
//
|
|
if (oemName.Length < NETBIOS_NAME_SIZE) {
|
|
RtlFillMemory(oemName.Buffer + oemName.Length, NETBIOS_NAME_SIZE - oemName.Length, ' ');
|
|
oemName.Length = NETBIOS_NAME_SIZE;
|
|
}
|
|
ASSERT(oemName.Length == NETBIOS_NAME_SIZE);
|
|
|
|
found = FALSE;
|
|
SMB_ACQUIRE_SPINLOCK(SmbCfg.SmbDeviceObject, Irql);
|
|
entry = SmbCfg.SmbDeviceObject->ClientList.Flink;
|
|
while (entry != &SmbCfg.SmbDeviceObject->ClientList) {
|
|
client = CONTAINING_RECORD(entry, SMB_CLIENT_ELEMENT, Linkage);
|
|
if (RtlEqualMemory(client->EndpointName, oemName.Buffer, oemName.Length)) {
|
|
found = TRUE;
|
|
}
|
|
|
|
entry = entry->Flink;
|
|
}
|
|
SMB_RELEASE_SPINLOCK(SmbCfg.SmbDeviceObject, Irql);
|
|
|
|
if (found) {
|
|
if (IsTcp6Available()) {
|
|
ipaddr->sin_family = SMB_AF_INET6;
|
|
ip6addr_getloopback(&ipaddr->ip6);
|
|
hton_ip6addr(&ipaddr->ip6);
|
|
} else {
|
|
ipaddr->sin_family = SMB_AF_INET;
|
|
ipaddr->ip4.sin4_addr = htonl(INADDR_ANY);
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
void SmbAsyncGetHostByName(
|
|
IN PUNICODE_STRING Name,
|
|
IN PSMB_GETHOST_CONTEXT Context
|
|
)
|
|
{
|
|
KIRQL Irql, CancelIrql;
|
|
PIRP DnsIrp = NULL, ClientIrp = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
SmbPrint(SMB_TRACE_CALL, ("SmbAsyncGetHostByName %Z\n", Name));
|
|
|
|
SmbAsyncStartTimer((PSMB_ASYNC_CONTEXT)Context, (PKDEFERRED_ROUTINE)SmbDnsTimeout);
|
|
if (inet_addr6W(Name->Buffer, &Context->ipaddr[0].ip6)) {
|
|
Context->ipaddr_num = 1;
|
|
Context->ipaddr[0].sin_family = SMB_AF_INET6;
|
|
Context->status = STATUS_SUCCESS;
|
|
Context->FQDN.Length = 0;
|
|
Context->FQDN.Buffer[0] = 0;
|
|
SmbAsyncCompleteRequest((PSMB_ASYNC_CONTEXT)Context);
|
|
return;
|
|
}
|
|
|
|
Context->ipaddr[0].ip4.sin4_addr = inet_addrW(Name->Buffer);
|
|
if (Context->ipaddr[0].ip4.sin4_addr != 0 && Context->ipaddr[0].ip4.sin4_addr != (ULONG)(-1)) {
|
|
Context->ipaddr_num = 1;
|
|
Context->ipaddr[0].sin_family = SMB_AF_INET;
|
|
Context->status = STATUS_SUCCESS;
|
|
Context->FQDN.Length = 0;
|
|
Context->FQDN.Buffer[0] = 0;
|
|
SmbAsyncCompleteRequest((PSMB_ASYNC_CONTEXT)Context);
|
|
return;
|
|
}
|
|
|
|
if (LookupLocalName(Name, &Context->ipaddr[0])) {
|
|
Context->ipaddr_num = 1;
|
|
Context->status = STATUS_SUCCESS;
|
|
Context->FQDN.Length = 0;
|
|
Context->FQDN.Buffer[0] = 0;
|
|
SmbAsyncCompleteRequest((PSMB_ASYNC_CONTEXT)Context);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The name is too long
|
|
//
|
|
if (Name->Length + sizeof(WCHAR) > Context->FQDN.MaximumLength) {
|
|
Context->status = STATUS_INVALID_PARAMETER;
|
|
SmbAsyncCompleteRequest((PSMB_ASYNC_CONTEXT)Context);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// It is not a IP address string, go to DNS resolver, to be implemented
|
|
//
|
|
ClientIrp = ((PSMB_CONNECT)Context->ClientContext)->PendingIRPs[SMB_PENDING_CONNECT];
|
|
ASSERT(ClientIrp);
|
|
|
|
SMB_ACQUIRE_SPINLOCK(&Dns, Irql);
|
|
IoAcquireCancelSpinLock(&CancelIrql);
|
|
if (ClientIrp->Cancel) {
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
|
|
//
|
|
// Already cancelled
|
|
//
|
|
Context->status = STATUS_CANCELLED;
|
|
SmbAsyncCompleteRequest((PSMB_ASYNC_CONTEXT)Context);
|
|
return;
|
|
}
|
|
|
|
IoSetCancelRoutine(ClientIrp, SmbCancelConnectAtDns);
|
|
|
|
DnsIrp = SmbDnsPopResolver();
|
|
if (NULL == DnsIrp) {
|
|
RtlCopyMemory(Context->FQDN.Buffer, Name->Buffer, Name->Length);
|
|
Context->FQDN.Length = Name->Length;
|
|
Context->FQDN.Buffer[Name->Length/sizeof(WCHAR)] = L'\0';
|
|
InsertTailList(&Dns.WaitingServerList, &Context->Linkage);
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
return;
|
|
}
|
|
|
|
IoSetCancelRoutine(DnsIrp, NULL);
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
|
|
//
|
|
// This guy will complete the Irp and release the spinlock!!!
|
|
//
|
|
SmbPassupDnsRequest(Name, Context, DnsIrp, Irql);
|
|
}
|
|
|
|
VOID
|
|
SmbCancelDns(
|
|
IN PDEVICE_OBJECT Device,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
KIRQL Irql;
|
|
LONG i;
|
|
BOOL Found = FALSE;
|
|
|
|
//
|
|
// Avoid deadlock, we need to release the spinlock first
|
|
//
|
|
SmbTrace(SMB_TRACE_DNS, ("Cancel DNS Irp %p", Irp));
|
|
SmbPrint(SMB_TRACE_DNS, ("Cancel DNS Irp %p\n", Irp));
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
//
|
|
// After the cancel spinlock is released, the IRP can be completed
|
|
// Check if it is still in our pending list
|
|
//
|
|
SMB_ACQUIRE_SPINLOCK(&Dns, Irql);
|
|
for (i = 0; i < Dns.ResolverNumber; i++) {
|
|
if (Dns.ResolverList[i] == Irp) {
|
|
Dns.ResolverNumber--;
|
|
Dns.ResolverList[i] = Dns.ResolverList[Dns.ResolverNumber];
|
|
Dns.ResolverList[Dns.ResolverNumber] = NULL;
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
|
|
if (Found) {
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
SmbTrace(SMB_TRACE_DNS, ("Complete Cancel DNS Irp %p", Irp));
|
|
SmbPrint(SMB_TRACE_DNS, ("Complete Cancel DNS Irp %p\n", Irp));
|
|
}
|
|
}
|
|
|
|
PSMB_GETHOST_CONTEXT
|
|
SmbDnsLookupGethostCtx(
|
|
PLIST_ENTRY queue,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
PLIST_ENTRY entry;
|
|
PIRP ClientIrp;
|
|
PSMB_GETHOST_CONTEXT Context;
|
|
|
|
//
|
|
// Spinlock should be held
|
|
//
|
|
ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
|
|
|
|
entry = queue->Flink;
|
|
while (entry != queue) {
|
|
Context = CONTAINING_RECORD(entry, SMB_GETHOST_CONTEXT, Linkage);
|
|
ClientIrp = ((PSMB_CONNECT)Context->ClientContext)->PendingIRPs[SMB_PENDING_CONNECT];
|
|
if (ClientIrp == Irp) {
|
|
return Context;
|
|
}
|
|
entry = entry->Flink;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
VOID
|
|
SmbCancelConnectAtDns(
|
|
IN PDEVICE_OBJECT Device,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PSMB_GETHOST_CONTEXT Context;
|
|
KIRQL Irql;
|
|
|
|
//
|
|
// Avoid deadlock, we need to release the spinlock first
|
|
//
|
|
SmbTrace(SMB_TRACE_OUTBOUND, ("Cancel Connect Irp %p", Irp));
|
|
SmbPrint(SMB_TRACE_OUTBOUND, ("Cancel Connect Irp %p\n", Irp));
|
|
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
SMB_ACQUIRE_SPINLOCK(&Dns, Irql);
|
|
Context = SmbDnsLookupGethostCtx(&Dns.BeingServedList, Irp);
|
|
if (NULL == Context) {
|
|
Context = SmbDnsLookupGethostCtx(&Dns.WaitingServerList, Irp);
|
|
}
|
|
if (NULL == Context) {
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
//
|
|
// This could happen. The DNS name resolution request could completed just before
|
|
// we acquire the spinlock Dns.Lock
|
|
//
|
|
// This ASSERT can be removed after we investigates one such case.
|
|
//
|
|
// ASSERT(0); Hit in the 04/03/2001 stress
|
|
SmbTrace(SMB_TRACE_OUTBOUND, ("Internal error: Cancel Connect Irp %p", Irp));
|
|
SmbPrint(SMB_TRACE_OUTBOUND, ("Internal error: Cancel Connect Irp %p\n", Irp));
|
|
return;
|
|
}
|
|
|
|
RemoveEntryList(&Context->Linkage);
|
|
InitializeListHead(&Context->Linkage);
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
|
|
Context->status = STATUS_CANCELLED;
|
|
SmbAsyncCompleteRequest((PSMB_ASYNC_CONTEXT)Context);
|
|
}
|
|
|
|
VOID
|
|
SmbDnsTimeout(
|
|
PKDPC Dpc,
|
|
PSMB_GETHOST_CONTEXT Context,
|
|
PVOID Unused1,
|
|
PVOID Unused2
|
|
)
|
|
{
|
|
KIRQL Irql;
|
|
BOOL Found;
|
|
|
|
//
|
|
// Be careful on the operations on the Context before we're sure it
|
|
// is still in the linked list.
|
|
// It could be completed and freed.
|
|
//
|
|
SMB_ACQUIRE_SPINLOCK(&Dns, Irql);
|
|
|
|
//
|
|
// Note: &Context->Linkage is safe since it doesn't access the
|
|
// storage allocated for Context!!!
|
|
//
|
|
Found = EntryIsInList(&Dns.BeingServedList, &Context->Linkage);
|
|
if (!Found) {
|
|
Found = EntryIsInList(&Dns.WaitingServerList, &Context->Linkage);
|
|
}
|
|
if (Found) {
|
|
//
|
|
// We're safe
|
|
//
|
|
RemoveEntryList(&Context->Linkage);
|
|
InitializeListHead(&Context->Linkage);
|
|
}
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
|
|
if (Found) {
|
|
Context->status = STATUS_BAD_NETWORK_PATH;
|
|
SmbAsyncCompleteRequest((PSMB_ASYNC_CONTEXT)Context);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbNewResolver(
|
|
PSMB_DEVICE Device,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
KIRQL Irql, CancelIrql;
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
ULONG Size;
|
|
PSMB_DNS_BUFFER DnsBuffer;
|
|
PLIST_ENTRY entry;
|
|
PSMB_GETHOST_CONTEXT Context;
|
|
PIRP ClientIrp;
|
|
|
|
if (NULL == Irp->MdlAddress) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
Size = MmGetMdlByteCount(Irp->MdlAddress);
|
|
if (Size < sizeof(SMB_DNS_BUFFER)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
DnsBuffer = (PSMB_DNS_BUFFER)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
|
|
if (NULL == DnsBuffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
SMB_ACQUIRE_SPINLOCK(&Dns, Irql);
|
|
if (!IsListEmpty(&Dns.BeingServedList) && DnsBuffer->Id) {
|
|
//
|
|
// Complete the pending DNS request being served by this resolver
|
|
//
|
|
entry = Dns.BeingServedList.Flink;
|
|
while (entry != &Dns.BeingServedList) {
|
|
Context = CONTAINING_RECORD(entry, SMB_GETHOST_CONTEXT, Linkage);
|
|
if (Context->Id == DnsBuffer->Id) {
|
|
break;
|
|
}
|
|
entry = entry->Flink;
|
|
}
|
|
if (entry != &Dns.BeingServedList) {
|
|
RemoveEntryList(&Context->Linkage);
|
|
InitializeListHead(&Context->Linkage);
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
ClientIrp = ((PSMB_CONNECT)Context->ClientContext)->PendingIRPs[SMB_PENDING_CONNECT];
|
|
ASSERT(ClientIrp);
|
|
|
|
IoAcquireCancelSpinLock(&CancelIrql);
|
|
IoSetCancelRoutine(ClientIrp, NULL);
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
|
|
if (ClientIrp->Cancel) {
|
|
Context->status = STATUS_CANCELLED;
|
|
} else {
|
|
if (DnsBuffer->Resolved) {
|
|
USHORT BytesToCopy;
|
|
|
|
Context->status = STATUS_SUCCESS;
|
|
Context->ipaddr_num = DnsBuffer->IpAddrsNum;
|
|
if (Context->ipaddr_num > SMB_MAX_IPADDRS_PER_HOST) {
|
|
ASSERT (0);
|
|
Context->ipaddr_num = SMB_MAX_IPADDRS_PER_HOST;
|
|
}
|
|
RtlCopyMemory (Context->ipaddr, DnsBuffer->IpAddrsList,
|
|
Context->ipaddr_num * sizeof(Context->ipaddr[0]));
|
|
|
|
if (DnsBuffer->NameLen) {
|
|
//
|
|
// Return the FQDN to RDR
|
|
//
|
|
Context->pUnicodeAddress->NameBufferType = NBT_WRITTEN;
|
|
|
|
BytesToCopy = (USHORT)DnsBuffer->NameLen * sizeof(WCHAR);
|
|
if (BytesToCopy > Context->pUnicodeAddress->RemoteName.MaximumLength) {
|
|
BytesToCopy = Context->pUnicodeAddress->RemoteName.MaximumLength - sizeof(WCHAR);
|
|
}
|
|
|
|
RtlCopyMemory(Context->pUnicodeAddress->RemoteName.Buffer,
|
|
DnsBuffer->Name, BytesToCopy);
|
|
Context->pUnicodeAddress->RemoteName.Buffer[BytesToCopy/sizeof(WCHAR)] = L'\0';
|
|
Context->pUnicodeAddress->RemoteName.Length = BytesToCopy;
|
|
}
|
|
} else {
|
|
Context->status = STATUS_BAD_NETWORK_PATH;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Is it better to start another thread?
|
|
// Risk: if the connection setup is stucked in tcpip,
|
|
// this thread won't be able to serve other DNS requests
|
|
//
|
|
SmbAsyncCompleteRequest((PSMB_ASYNC_CONTEXT)Context);
|
|
|
|
SMB_ACQUIRE_SPINLOCK(&Dns, Irql);
|
|
}
|
|
}
|
|
|
|
if (IsListEmpty(&Dns.WaitingServerList)) {
|
|
//
|
|
// We need to queue the IRP, setup the cancel routine.
|
|
//
|
|
IoAcquireCancelSpinLock(&CancelIrql);
|
|
if (Irp->Cancel) {
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
SmbTrace(SMB_TRACE_DNS, ("DNS Irp %p is cancelled", Irp));
|
|
SmbPrint(SMB_TRACE_DNS, ("DNS Irp %p is cancelled\n", Irp));
|
|
return STATUS_CANCELLED;
|
|
}
|
|
IoSetCancelRoutine(Irp, SmbCancelDns);
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
|
|
status = SmbDnsPushResolver(Irp);
|
|
if (NT_SUCCESS(status)) {
|
|
status = STATUS_PENDING;
|
|
} else {
|
|
IoAcquireCancelSpinLock(&CancelIrql);
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
}
|
|
SMB_RELEASE_SPINLOCK(&Dns, Irql);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// We have another guy to be served
|
|
//
|
|
Context = CONTAINING_RECORD(Dns.WaitingServerList.Flink, SMB_GETHOST_CONTEXT, Linkage);
|
|
RemoveEntryList(&Context->Linkage);
|
|
InitializeListHead(&Context->Linkage);
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
//
|
|
// This guy will complete the Irp and release the spinlock!!!
|
|
//
|
|
SmbPassupDnsRequest(&Context->FQDN, Context, Irp, Irql);
|
|
|
|
//
|
|
// Avoid double completion
|
|
//
|
|
return STATUS_PENDING;
|
|
}
|