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.
1516 lines
44 KiB
1516 lines
44 KiB
/*++
|
|
|
|
Copyright (c) 1989-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ntpnp.c
|
|
|
|
Abstract:
|
|
|
|
Plug & Play
|
|
|
|
Author:
|
|
|
|
Jiandong Ruan
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "ntpnp.tmh"
|
|
|
|
#define TL_INSTANCE 0
|
|
|
|
ULONG
|
|
SmbGetInterfaceIndex(
|
|
IN PUNICODE_STRING ucName
|
|
);
|
|
|
|
ULONG
|
|
SmbGetInterfaceIndexV4(
|
|
IN PUNICODE_STRING ucName
|
|
);
|
|
|
|
ULONG
|
|
SmbGetInterfaceIndexV6(
|
|
IN PUNICODE_STRING ucName
|
|
);
|
|
|
|
NTSTATUS
|
|
SmbBatchedSetBindingInfo(
|
|
PSMB_DEVICE Device,
|
|
ULONG RequestType,
|
|
PWSTR MultiSZBindList
|
|
);
|
|
|
|
#pragma alloc_text(PAGE, SmbBindHandler)
|
|
#pragma alloc_text(PAGE, SmbGetInterfaceIndex)
|
|
#pragma alloc_text(PAGE, SmbGetInterfaceIndexV6)
|
|
#pragma alloc_text(PAGE, SmbGetInterfaceIndexV4)
|
|
|
|
NTSTATUS
|
|
SmbDeviceAdd(
|
|
PUNICODE_STRING pDeviceName
|
|
);
|
|
|
|
NTSTATUS
|
|
SmbDeviceDel(
|
|
PUNICODE_STRING pDeviceName
|
|
);
|
|
|
|
NTSTATUS
|
|
SmbUpcaseUnicodeStringNP(
|
|
IN OUT PUNICODE_STRING dest,
|
|
IN PUNICODE_STRING src
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
dest->MaximumLength = src->MaximumLength;
|
|
dest->Buffer = ExAllocatePoolWithTag(NonPagedPool, dest->MaximumLength, SMB_TCP_DEVICE_POOL_TAG);
|
|
if (NULL == dest->Buffer) {
|
|
return (STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
status = RtlUpcaseUnicodeString(dest, src, FALSE);
|
|
if (STATUS_SUCCESS != status) {
|
|
ExFreePool(dest->Buffer);
|
|
dest->Buffer = NULL;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
PSMB_TCP_DEVICE
|
|
SmbFindAndReferenceInterface(
|
|
PUNICODE_STRING Name
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find the IPv6 interfaces in IPDeviceList
|
|
SpinLock should be held while calling this function.
|
|
|
|
Arguments:
|
|
|
|
Name the device name
|
|
the buffer should be non-paged
|
|
|
|
Return Value:
|
|
|
|
NULL if we cannot find it
|
|
non-NULL otherwise
|
|
|
|
--*/
|
|
{
|
|
PSMB_TCP_DEVICE pIf = NULL;
|
|
PLIST_ENTRY Entry = NULL;
|
|
|
|
ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
|
|
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbFindDevice: looking for %Z\n", Name));
|
|
Entry = SmbCfg.IPDeviceList.Flink;
|
|
while(Entry != &SmbCfg.IPDeviceList) {
|
|
pIf = CONTAINING_RECORD(Entry, SMB_TCP_DEVICE, Linkage);
|
|
|
|
//
|
|
// We can safely call RtlEqualMemory since both buffers are non-paged and resident.
|
|
//
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbFindDevice: compare with %Z\n", &pIf->AdapterName));
|
|
if (pIf->AdapterName.Length == Name->Length &&
|
|
RtlEqualMemory(pIf->AdapterName.Buffer, Name->Buffer, Name->Length)) {
|
|
SmbReferenceObject((PSMB_OBJECT)pIf, SMB_REF_FIND);
|
|
return pIf;
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
VOID
|
|
SmbIp6AddressArrival(
|
|
PTDI_ADDRESS_IP6 Addr,
|
|
PUNICODE_STRING pDeviceName,
|
|
PTDI_PNP_CONTEXT Context
|
|
)
|
|
{
|
|
UNICODE_STRING ucName;
|
|
NTSTATUS status;
|
|
PSMB_TCP_DEVICE pIf;
|
|
KIRQL Irql;
|
|
BOOL NotifyClient = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
SmbTrace(SMB_TRACE_PNP, ("%!IPV6ADDR! for %Z", (PVOID)&(Addr->sin6_addr), pDeviceName));
|
|
|
|
SmbInitTCP6(&SmbCfg.SmbDeviceObject->Tcp6, SmbCfg.SmbDeviceObject->Port, SmbCfg.SmbDeviceObject);
|
|
|
|
status = SmbUpcaseUnicodeStringNP(&ucName, pDeviceName);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
KeAcquireSpinLock(&SmbCfg.Lock, &Irql);
|
|
pIf = SmbFindAndReferenceInterface(&ucName);
|
|
KeReleaseSpinLock(&SmbCfg.Lock, Irql);
|
|
if (NULL == pIf) {
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!pIf->AddressPlumbed) {
|
|
pIf->PrimaryIpAddress.sin_family = SMB_AF_INET6;
|
|
|
|
RtlCopyMemory(pIf->PrimaryIpAddress.ip6.sin6_addr,
|
|
Addr->sin6_addr,
|
|
sizeof(pIf->PrimaryIpAddress.ip6.sin6_addr));
|
|
pIf->PrimaryIpAddress.ip6.sin6_scope_id = Addr->sin6_scope_id;
|
|
pIf->AddressPlumbed = TRUE;
|
|
NotifyClient = (0 == SmbCfg.IPAddressNumber);
|
|
SmbCfg.IPAddressNumber++;
|
|
SmbCfg.IPv6AddressNumber++;
|
|
|
|
//
|
|
// Don't use SmbPrint to print a WSTR at DISPATCH_LEVEL. Only SmbTrace is usable
|
|
//
|
|
SmbTrace(SMB_TRACE_PNP, ("New IPv6 address %!IPV6ADDR! for %Z", (PVOID)&(Addr->sin6_addr), &ucName));
|
|
}
|
|
pIf->InterfaceIndex = SmbGetInterfaceIndex(&pIf->AdapterName);
|
|
SmbDereferenceObject((PSMB_OBJECT)pIf, SMB_REF_FIND);
|
|
|
|
//
|
|
// Query the loopback interface index if it hasn't been done
|
|
//
|
|
if (SmbCfg.SmbDeviceObject->Tcp6.LoopbackInterfaceIndex == INVALID_INTERFACE_INDEX) {
|
|
if (SmbCfg.SmbDeviceObject->Tcp6.FastQuery) {
|
|
SMB_IP6_ADDRESS loopback;
|
|
ULONG IfIndex, Metric;
|
|
|
|
ip6addr_getloopback(&loopback);
|
|
hton_ip6addr(&loopback);
|
|
status = ((PIP6FASTQUERY)(SmbCfg.SmbDeviceObject->Tcp6.FastQuery))(&loopback, &IfIndex, &Metric);
|
|
if (status == STATUS_SUCCESS) {
|
|
SmbCfg.SmbDeviceObject->Tcp6.LoopbackInterfaceIndex = IfIndex;
|
|
SmbPrint(SMB_TRACE_TCP, ("Loopback Interface Index = %d\n", IfIndex));
|
|
SmbTrace(SMB_TRACE_TCP, ("Loopback Interface Index = %d", IfIndex));
|
|
} else {
|
|
SmbPrint(SMB_TRACE_TCP, ("Query loopback Interface Index returns 0x%08lx\n", status));
|
|
SmbTrace(SMB_TRACE_TCP, ("Query loopback Interface Index returns %!status!", status));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NotifyClient) {
|
|
SmbPrint(SMB_TRACE_PNP, ("Registraion: Notify Client\n"));
|
|
SmbTdiRegister(SmbCfg.SmbDeviceObject);
|
|
}
|
|
|
|
cleanup:
|
|
if (ucName.Buffer) {
|
|
ExFreePool(ucName.Buffer);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SmbIp6AddressDeletion(
|
|
PTDI_ADDRESS_IP6 Addr,
|
|
PUNICODE_STRING pDeviceName,
|
|
PTDI_PNP_CONTEXT Context
|
|
)
|
|
{
|
|
UNICODE_STRING ucName;
|
|
NTSTATUS status;
|
|
PSMB_TCP_DEVICE pIf;
|
|
KIRQL Irql;
|
|
BOOL NotifyClient = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
SmbTrace(SMB_TRACE_PNP, ("%!IPV6ADDR! for %Z", (PVOID)&(Addr->sin6_addr), pDeviceName));
|
|
|
|
status = SmbUpcaseUnicodeStringNP(&ucName, pDeviceName);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
KeAcquireSpinLock(&SmbCfg.Lock, &Irql);
|
|
pIf = SmbFindAndReferenceInterface(&ucName);
|
|
KeReleaseSpinLock(&SmbCfg.Lock, Irql);
|
|
if (NULL == pIf) {
|
|
goto cleanup;
|
|
}
|
|
|
|
if (pIf->AddressPlumbed &&
|
|
RtlEqualMemory(pIf->PrimaryIpAddress.ip6.sin6_addr,
|
|
Addr->sin6_addr,
|
|
sizeof(pIf->PrimaryIpAddress.ip6.sin6_addr))) {
|
|
pIf->AddressPlumbed = FALSE;
|
|
SmbCfg.IPAddressNumber--;
|
|
SmbCfg.IPv6AddressNumber--;
|
|
NotifyClient = (0 == SmbCfg.IPAddressNumber);
|
|
|
|
//
|
|
// Don't use SmbPrint to print a WSTR at DISPATCH_LEVEL. Only SmbTrace is usable
|
|
//
|
|
SmbTrace(SMB_TRACE_PNP, ("Delete IPv6 address %!IPV6ADDR! for %Z", (PVOID)&(Addr->sin6_addr), &ucName));
|
|
}
|
|
SmbDereferenceObject((PSMB_OBJECT)pIf, SMB_REF_FIND);
|
|
|
|
if (NotifyClient) {
|
|
SmbPrint(SMB_TRACE_PNP, ("Deregistraion: Notify Client\n"));
|
|
SmbTdiDeregister(SmbCfg.SmbDeviceObject);
|
|
}
|
|
|
|
cleanup:
|
|
if (ucName.Buffer) {
|
|
ExFreePool(ucName.Buffer);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SmbIp4AddressArrival(
|
|
PTDI_ADDRESS_IP Addr,
|
|
PUNICODE_STRING pDeviceName,
|
|
PTDI_PNP_CONTEXT Context
|
|
)
|
|
{
|
|
UNICODE_STRING ucName;
|
|
NTSTATUS status;
|
|
PSMB_TCP_DEVICE pIf;
|
|
KIRQL Irql;
|
|
BOOL NotifyClient = FALSE;
|
|
CHAR Buffer[16];
|
|
|
|
Inet_ntoa_nb(Addr->in_addr, Buffer);
|
|
Buffer[15] =0;
|
|
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbIp4AddressArrival: %s %Z\n", Buffer, pDeviceName));
|
|
SmbTrace(SMB_TRACE_PNP, ("%!ipaddr! %Z", Addr->in_addr, pDeviceName));
|
|
|
|
SmbInitTCP4(&SmbCfg.SmbDeviceObject->Tcp4, SmbCfg.SmbDeviceObject->Port, SmbCfg.SmbDeviceObject);
|
|
|
|
if (INADDR_NONE == Addr->in_addr) {
|
|
return;
|
|
}
|
|
|
|
status = SmbUpcaseUnicodeStringNP(&ucName, pDeviceName);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
KeAcquireSpinLock(&SmbCfg.Lock, &Irql);
|
|
pIf = SmbFindAndReferenceInterface(&ucName);
|
|
KeReleaseSpinLock(&SmbCfg.Lock, Irql);
|
|
if (NULL == pIf) {
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!pIf->AddressPlumbed) {
|
|
pIf->PrimaryIpAddress.sin_family = SMB_AF_INET;
|
|
|
|
pIf->PrimaryIpAddress.ip4.sin4_addr = Addr->in_addr;
|
|
pIf->AddressPlumbed = TRUE;
|
|
NotifyClient = (0 == SmbCfg.IPAddressNumber);
|
|
SmbCfg.IPAddressNumber++;
|
|
SmbCfg.IPv4AddressNumber++;
|
|
|
|
//
|
|
// Don't use SmbPrint to print a WSTR at DISPATCH_LEVEL. Only SmbTrace is usable
|
|
//
|
|
SmbTrace(SMB_TRACE_PNP, ("New IPv4 address %s for %Z", Buffer, &ucName));
|
|
}
|
|
pIf->InterfaceIndex = SmbGetInterfaceIndex(&pIf->AdapterName);
|
|
SmbDereferenceObject((PSMB_OBJECT)pIf, SMB_REF_FIND);
|
|
|
|
//
|
|
// Query the loopback interface index if it hasn't been done
|
|
//
|
|
if (SmbCfg.SmbDeviceObject->Tcp4.LoopbackInterfaceIndex == INVALID_INTERFACE_INDEX) {
|
|
if (SmbCfg.SmbDeviceObject->Tcp4.FastQuery) {
|
|
ULONG IfIndex, Metric;
|
|
|
|
status = ((PIP4FASTQUERY)(SmbCfg.SmbDeviceObject->Tcp4.FastQuery))(
|
|
ntohl(INADDR_LOOPBACK), &IfIndex, &Metric);
|
|
if (status == STATUS_SUCCESS) {
|
|
SmbCfg.SmbDeviceObject->Tcp4.LoopbackInterfaceIndex = IfIndex;
|
|
SmbPrint(SMB_TRACE_TCP, ("Loopback Interface Index = %d\n", IfIndex));
|
|
SmbTrace(SMB_TRACE_TCP, ("Loopback Interface Index = %d", IfIndex));
|
|
} else {
|
|
SmbPrint(SMB_TRACE_TCP, ("Query loopback Interface Index returns 0x%08lx\n", status));
|
|
SmbTrace(SMB_TRACE_TCP, ("Query loopback Interface Index returns %!status!", status));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NotifyClient) {
|
|
SmbPrint(SMB_TRACE_PNP, ("Registraion: Notify Client\n"));
|
|
SmbTdiRegister(SmbCfg.SmbDeviceObject);
|
|
}
|
|
|
|
cleanup:
|
|
if (ucName.Buffer) {
|
|
ExFreePool(ucName.Buffer);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SmbIp4AddressDeletion(
|
|
PTDI_ADDRESS_IP Addr,
|
|
PUNICODE_STRING pDeviceName,
|
|
PTDI_PNP_CONTEXT Context
|
|
)
|
|
{
|
|
UNICODE_STRING ucName;
|
|
NTSTATUS status;
|
|
PSMB_TCP_DEVICE pIf;
|
|
KIRQL Irql;
|
|
BOOL NotifyClient = FALSE;
|
|
CHAR Buffer[16];
|
|
|
|
Inet_ntoa_nb(Addr->in_addr, Buffer);
|
|
Buffer[15] =0;
|
|
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbIp4AddressDeletion: %s %Z\n", Buffer, pDeviceName));
|
|
SmbTrace(SMB_TRACE_PNP, ("%!ipaddr! %Z", Addr->in_addr, pDeviceName));
|
|
if (INADDR_NONE == Addr->in_addr) {
|
|
return;
|
|
}
|
|
|
|
status = SmbUpcaseUnicodeStringNP(&ucName, pDeviceName);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
KeAcquireSpinLock(&SmbCfg.Lock, &Irql);
|
|
pIf = SmbFindAndReferenceInterface(&ucName);
|
|
KeReleaseSpinLock(&SmbCfg.Lock, Irql);
|
|
if (NULL == pIf) {
|
|
goto cleanup;
|
|
}
|
|
|
|
if (pIf->AddressPlumbed && pIf->PrimaryIpAddress.ip4.sin4_addr == Addr->in_addr) {
|
|
pIf->AddressPlumbed = FALSE;
|
|
SmbCfg.IPAddressNumber--;
|
|
SmbCfg.IPv4AddressNumber--;
|
|
NotifyClient = (0 == SmbCfg.IPAddressNumber);
|
|
|
|
//
|
|
// Don't use SmbPrint to print a WSTR at DISPATCH_LEVEL. Only SmbTrace is usable
|
|
//
|
|
SmbTrace(SMB_TRACE_PNP, ("Delete IPv4 address %s for %Z", Buffer, &ucName));
|
|
}
|
|
SmbDereferenceObject((PSMB_OBJECT)pIf, SMB_REF_FIND);
|
|
|
|
if (NotifyClient) {
|
|
SmbPrint(SMB_TRACE_PNP, ("Deregistraion: Notify Client\n"));
|
|
SmbTdiDeregister(SmbCfg.SmbDeviceObject);
|
|
}
|
|
|
|
cleanup:
|
|
if (ucName.Buffer) {
|
|
ExFreePool(ucName.Buffer);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SmbAddressArrival(
|
|
PTA_ADDRESS Addr,
|
|
PUNICODE_STRING pDeviceName,
|
|
PTDI_PNP_CONTEXT Context
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
switch (Addr->AddressType) {
|
|
case TDI_ADDRESS_TYPE_IP6:
|
|
SmbIp6AddressArrival ((PTDI_ADDRESS_IP6)Addr->Address, pDeviceName, Context);
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_IP:
|
|
SmbIp4AddressArrival ((PTDI_ADDRESS_IP)Addr->Address, pDeviceName, Context);
|
|
break;
|
|
|
|
default:
|
|
goto cleanup;
|
|
}
|
|
|
|
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
|
|
|
|
//
|
|
// Change the binding
|
|
//
|
|
KeEnterCriticalRegion ();
|
|
ExAcquireResourceExclusiveLite (&SmbCfg.Resource, TRUE);
|
|
SmbBatchedSetBindingInfo (SmbCfg.SmbDeviceObject, SMB_CLIENT, SmbCfg.SmbDeviceObject->ClientBinding);
|
|
SmbBatchedSetBindingInfo (SmbCfg.SmbDeviceObject, SMB_SERVER, SmbCfg.SmbDeviceObject->ServerBinding);
|
|
ExReleaseResourceLite (&SmbCfg.Resource);
|
|
KeLeaveCriticalRegion ();
|
|
|
|
cleanup:
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
SmbAddressDeletion(
|
|
PTA_ADDRESS Addr,
|
|
PUNICODE_STRING pDeviceName,
|
|
PTDI_PNP_CONTEXT Context
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
switch (Addr->AddressType) {
|
|
case TDI_ADDRESS_TYPE_IP6:
|
|
SmbIp6AddressDeletion ((PTDI_ADDRESS_IP6)Addr->Address, pDeviceName, Context);
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_IP:
|
|
SmbIp4AddressDeletion ((PTDI_ADDRESS_IP)Addr->Address, pDeviceName, Context);
|
|
break;
|
|
|
|
default:
|
|
goto cleanup;
|
|
}
|
|
|
|
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
|
|
|
|
//
|
|
// Change the binding
|
|
//
|
|
KeEnterCriticalRegion ();
|
|
ExAcquireResourceExclusiveLite (&SmbCfg.Resource, TRUE);
|
|
SmbBatchedSetBindingInfo (SmbCfg.SmbDeviceObject, SMB_CLIENT, SmbCfg.SmbDeviceObject->ClientBinding);
|
|
SmbBatchedSetBindingInfo (SmbCfg.SmbDeviceObject, SMB_SERVER, SmbCfg.SmbDeviceObject->ServerBinding);
|
|
ExReleaseResourceLite (&SmbCfg.Resource);
|
|
KeLeaveCriticalRegion ();
|
|
|
|
cleanup:
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
SmbBindHandler(
|
|
TDI_PNP_OPCODE PnPOpCode,
|
|
PUNICODE_STRING pDeviceName,
|
|
PWSTR MultiSZBindList
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING ucIPDevice;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (SmbCfg.Unloading) {
|
|
return;
|
|
}
|
|
|
|
switch(PnPOpCode) {
|
|
case TDI_PNP_OP_ADD:
|
|
status = SmbDeviceAdd(pDeviceName);
|
|
SmbTrace(SMB_TRACE_PNP, ("return %!status! for %Z", status, pDeviceName));
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbDeviceAdd return 0x%08lx for %Z\n", status, pDeviceName));
|
|
break;
|
|
|
|
case TDI_PNP_OP_DEL:
|
|
status = SmbDeviceDel(pDeviceName);
|
|
SmbTrace(SMB_TRACE_PNP, ("SmbDeviceDel return %!status! for %Z", status, pDeviceName));
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbDeviceDel return 0x%08lx for %Z\n", status, pDeviceName));
|
|
break;
|
|
|
|
case TDI_PNP_OP_PROVIDERREADY:
|
|
SmbTrace(SMB_TRACE_PNP, ("Provider %Z is ready", pDeviceName));
|
|
SmbPrint(SMB_TRACE_PNP, ("Provider %Z is ready\n", pDeviceName));
|
|
|
|
RtlInitUnicodeString(&ucIPDevice, DD_IPV6_DEVICE_NAME);
|
|
if (RtlEqualUnicodeString(pDeviceName, &ucIPDevice, TRUE)) {
|
|
SmbInitTCP6(&SmbCfg.SmbDeviceObject->Tcp6, SmbCfg.SmbDeviceObject->Port, SmbCfg.SmbDeviceObject);
|
|
if (!SmbCfg.ProviderReady++) {
|
|
TdiProviderReady(SmbCfg.TdiProviderHandle);
|
|
}
|
|
} else {
|
|
RtlInitUnicodeString(&ucIPDevice, DD_IP_DEVICE_NAME);
|
|
if (RtlEqualUnicodeString(pDeviceName, &ucIPDevice, TRUE)) {
|
|
SmbInitTCP4(&SmbCfg.SmbDeviceObject->Tcp4, SmbCfg.SmbDeviceObject->Port, SmbCfg.SmbDeviceObject);
|
|
if (!SmbCfg.ProviderReady++) {
|
|
TdiProviderReady(SmbCfg.TdiProviderHandle);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TDI_PNP_OP_UPDATE:
|
|
case TDI_PNP_OP_NETREADY:
|
|
/* Nothing to do */
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SmbShutdownPnP(
|
|
VOID
|
|
)
|
|
{
|
|
PLIST_ENTRY entry;
|
|
PSMB_TCP_DEVICE pIf;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(SmbCfg.Unloading);
|
|
|
|
while(!IsListEmpty(&SmbCfg.IPDeviceList)) {
|
|
entry = RemoveHeadList(&SmbCfg.IPDeviceList);
|
|
InsertTailList(&SmbCfg.PendingDeleteIPDeviceList, entry);
|
|
|
|
pIf = CONTAINING_RECORD(entry, SMB_TCP_DEVICE, Linkage);
|
|
|
|
ASSERT(pIf->RefCount == 1);
|
|
SmbDereferenceObject((PSMB_OBJECT)pIf, SMB_REF_CREATE);
|
|
}
|
|
ASSERT(IsListEmpty(&SmbCfg.PendingDeleteIPDeviceList));
|
|
}
|
|
|
|
NTSTATUS
|
|
CheckRegistryBinding(
|
|
PUNICODE_STRING pDeviceName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine read in the HKLM\System\CCS\Services\SMB6\Linkage\Bind and check if pDeviceName is in the
|
|
binding list.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if pDeviceName is in the binding list
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
DWORD length;
|
|
DWORD type;
|
|
WCHAR *pBindingList = NULL;
|
|
WCHAR *pStart = NULL;
|
|
WCHAR *pEnd;
|
|
UNICODE_STRING ucName;
|
|
|
|
PAGED_CODE();
|
|
|
|
length = 0;
|
|
type = REG_MULTI_SZ;
|
|
pBindingList = NULL;
|
|
|
|
status = SmbReadRegistry(
|
|
SmbCfg.LinkageKey,
|
|
L"Bind",
|
|
&type,
|
|
&length,
|
|
&pBindingList
|
|
);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
pStart = pBindingList;
|
|
pEnd = (WCHAR*)(((PUCHAR)pBindingList) + length);
|
|
|
|
while (*pBindingList && pBindingList < pEnd) {
|
|
RtlInitUnicodeString(&ucName, pBindingList);
|
|
|
|
if (RtlEqualUnicodeString(&ucName, pDeviceName, TRUE)) {
|
|
ExFreePool(pStart);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
pBindingList += (ucName.Length / sizeof(WCHAR)) + 1;
|
|
}
|
|
|
|
cleanup:
|
|
if (pStart) {
|
|
ExFreePool(pStart);
|
|
}
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
ULONG
|
|
SmbGetInterfaceIndexV4(
|
|
IN PUNICODE_STRING ucName
|
|
)
|
|
{
|
|
PIP_INTERFACE_INFO IpInfo;
|
|
ULONG Size;
|
|
ULONG Index;
|
|
LONG Entries;
|
|
LONG i;
|
|
NTSTATUS status;
|
|
UNICODE_STRING ucIpDeviceName;
|
|
|
|
PAGED_CODE();
|
|
|
|
Entries = SmbCfg.IPDeviceNumber;
|
|
do {
|
|
Size = Entries * sizeof(IP_ADAPTER_INDEX_MAP) + sizeof(ULONG);
|
|
IpInfo = (PIP_INTERFACE_INFO)ExAllocatePoolWithTag(NonPagedPool, Size, '6BMS');
|
|
if (NULL == IpInfo) {
|
|
SmbTrace(SMB_TRACE_TCP, ("out of memory"));
|
|
return INVALID_INTERFACE_INDEX;
|
|
}
|
|
|
|
status = SmbSendIoctl(
|
|
SmbCfg.SmbDeviceObject->Tcp4.IPControlFileObject,
|
|
IOCTL_IP_INTERFACE_INFO,
|
|
NULL,
|
|
0,
|
|
IpInfo,
|
|
&Size
|
|
);
|
|
if (STATUS_BUFFER_OVERFLOW != status) {
|
|
break;
|
|
}
|
|
|
|
ExFreePool(IpInfo);
|
|
IpInfo = NULL;
|
|
Entries += 2;
|
|
} while(Entries < 128);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ExFreePool(IpInfo);
|
|
IpInfo = NULL;
|
|
return INVALID_INTERFACE_INDEX;
|
|
}
|
|
|
|
Index = INVALID_INTERFACE_INDEX;
|
|
for (i = 0; i < IpInfo->NumAdapters; i++) {
|
|
RtlInitUnicodeString(&ucIpDeviceName, IpInfo->Adapter[i].Name);
|
|
if (RtlEqualUnicodeString(ucName, &ucIpDeviceName, TRUE)) {
|
|
Index = IpInfo->Adapter[i].Index;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ExFreePool(IpInfo);
|
|
IpInfo = NULL;
|
|
return Index;
|
|
}
|
|
|
|
ULONG
|
|
SmbGetInterfaceIndexV6(
|
|
IN PUNICODE_STRING ucName
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return INVALID_INTERFACE_INDEX;
|
|
}
|
|
|
|
ULONG
|
|
SmbGetInterfaceIndex(
|
|
IN PUNICODE_STRING ucName
|
|
)
|
|
{
|
|
ULONG Index;
|
|
|
|
PAGED_CODE();
|
|
|
|
#if 0
|
|
Index = SmbGetInterfaceIndexV4(ucName);
|
|
SmbPrint(SMB_TRACE_TCP, ("IPV4: returns InterfaceIndex 0x%04lx for %Z\n", Index, ucName));
|
|
SmbTrace(SMB_TRACE_TCP, ("IPV4: returns InterfaceIndex 0x%04lx for %Z", Index, ucName));
|
|
if (Index != INVALID_INTERFACE_INDEX) {
|
|
return Index;
|
|
}
|
|
|
|
Index = SmbGetInterfaceIndexV6(ucName);
|
|
SmbPrint(SMB_TRACE_TCP, ("IPV6: returns InterfaceIndex 0x%04lx for %Z\n", Index, ucName));
|
|
SmbTrace(SMB_TRACE_TCP, ("IPV6: returns InterfaceIndex 0x%04lx for %Z", Index, ucName));
|
|
#else
|
|
//
|
|
// we have to use the following logic due to a compiler bug
|
|
// Hack!!!
|
|
//
|
|
if (ucName->Length >= 28 && ucName->Buffer[13] == L'6') {
|
|
Index = SmbGetInterfaceIndexV6(ucName);
|
|
SmbPrint(SMB_TRACE_TCP, ("IPV6: returns InterfaceIndex 0x%04lx for %Z\n", Index, ucName));
|
|
SmbTrace(SMB_TRACE_TCP, ("IPV6: returns InterfaceIndex 0x%04lx for %Z", Index, ucName));
|
|
} else {
|
|
Index = SmbGetInterfaceIndexV4(ucName);
|
|
SmbPrint(SMB_TRACE_TCP, ("IPV4: returns InterfaceIndex 0x%04lx for %Z\n", Index, ucName));
|
|
SmbTrace(SMB_TRACE_TCP, ("IPV4: returns InterfaceIndex 0x%04lx for %Z", Index, ucName));
|
|
}
|
|
#endif
|
|
return Index;
|
|
}
|
|
|
|
VOID
|
|
SmbDeleteTcpDevice(PSMB_TCP_DEVICE pIf)
|
|
{
|
|
KIRQL Irql;
|
|
|
|
SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
|
|
|
|
ASSERT(EntryIsInList(&SmbCfg.PendingDeleteIPDeviceList, &pIf->Linkage));
|
|
RemoveEntryList(&pIf->Linkage);
|
|
SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
|
|
|
|
ExFreePool(pIf);
|
|
|
|
SmbPrint(SMB_TRACE_CALL, ("SmbDeleteTcpDevice: free tcp device %p\n", pIf));
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmbDeviceAdd(
|
|
PUNICODE_STRING pDeviceName
|
|
)
|
|
{
|
|
KIRQL Irql;
|
|
PLIST_ENTRY Entry = NULL;
|
|
PSMB_TCP_DEVICE pIf = NULL;
|
|
PSMB_TCP_DEVICE pNewIf = NULL;
|
|
DWORD Size;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
pNewIf = NULL;
|
|
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbDeviceAdd: %Z\n", pDeviceName));
|
|
SmbTrace(SMB_TRACE_PNP, ("%Z", pDeviceName));
|
|
|
|
/*
|
|
No need to check it since TDI has already done it before calling us
|
|
|
|
status = CheckRegistryBinding(pDeviceName);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
*/
|
|
|
|
Size = ALIGN(sizeof(SMB_TCP_DEVICE)) + pDeviceName->MaximumLength;
|
|
pNewIf = ExAllocatePoolWithTag(NonPagedPool, Size, SMB_TCP_DEVICE_POOL_TAG);
|
|
if (pNewIf == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
RtlZeroMemory(pNewIf, Size);
|
|
|
|
SmbInitializeObject((PSMB_OBJECT)pNewIf, TAG_TCP_DEVICE, (PSMB_OBJECT_CLEANUP)SmbDeleteTcpDevice);
|
|
|
|
pNewIf->AdapterName.Length = 0;
|
|
pNewIf->AdapterName.MaximumLength = pDeviceName->MaximumLength;
|
|
pNewIf->AdapterName.Buffer = (WCHAR*)((PUCHAR)pNewIf + ALIGN(sizeof(SMB_TCP_DEVICE)));
|
|
InitializeListHead(&pNewIf->Linkage);
|
|
|
|
status = RtlUpcaseUnicodeString(&pNewIf->AdapterName, pDeviceName, FALSE);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
KeAcquireSpinLock(&SmbCfg.Lock, &Irql);
|
|
Entry = SmbCfg.IPDeviceList.Flink;
|
|
while(Entry != &SmbCfg.IPDeviceList) {
|
|
pIf = CONTAINING_RECORD(Entry, SMB_TCP_DEVICE, Linkage);
|
|
|
|
//
|
|
// We can safely call RtlEqualMemory since both buffers are non-paged and resident.
|
|
//
|
|
if (pIf->AdapterName.Length == pNewIf->AdapterName.Length &&
|
|
RtlEqualMemory(pIf->AdapterName.Buffer, pNewIf->AdapterName.Buffer, pNewIf->AdapterName.Length)) {
|
|
ExFreePool(pNewIf);
|
|
pNewIf = NULL;
|
|
break;
|
|
}
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
if (pNewIf) {
|
|
SmbCfg.IPDeviceNumber++;
|
|
InsertTailList(&SmbCfg.IPDeviceList, &pNewIf->Linkage);
|
|
SmbTrace(SMB_TRACE_PNP, ("Add device %Z", &pNewIf->AdapterName));
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbDeviceAdd: Add %Z\n", &pNewIf->AdapterName));
|
|
}
|
|
KeReleaseSpinLock(&SmbCfg.Lock, Irql);
|
|
|
|
SmbInitTCP4(&SmbCfg.SmbDeviceObject->Tcp4, SmbCfg.SmbDeviceObject->Port, SmbCfg.SmbDeviceObject);
|
|
SmbInitTCP6(&SmbCfg.SmbDeviceObject->Tcp6, SmbCfg.SmbDeviceObject->Port, SmbCfg.SmbDeviceObject);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
cleanup:
|
|
if (pNewIf) {
|
|
ExFreePool(pNewIf);
|
|
}
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbDeviceDel(
|
|
PUNICODE_STRING pDeviceName
|
|
)
|
|
{
|
|
KIRQL Irql;
|
|
UNICODE_STRING ucName = { 0 };
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PSMB_TCP_DEVICE pIf = NULL;
|
|
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbDeviceDel: %Z\n", pDeviceName));
|
|
SmbTrace(SMB_TRACE_PNP, ("%Z", pDeviceName));
|
|
|
|
ucName.MaximumLength = pDeviceName->MaximumLength;
|
|
ucName.Buffer = ExAllocatePoolWithTag(NonPagedPool, ucName.MaximumLength, SMB_TCP_DEVICE_POOL_TAG);
|
|
if (NULL == ucName.Buffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = RtlUpcaseUnicodeString(&ucName, pDeviceName, FALSE);
|
|
BAIL_OUT_ON_ERROR(status);
|
|
|
|
KeAcquireSpinLock(&SmbCfg.Lock, &Irql);
|
|
pIf = SmbFindAndReferenceInterface(&ucName);
|
|
KeReleaseSpinLock(&SmbCfg.Lock, Irql);
|
|
if (NULL == pIf) {
|
|
status = STATUS_NOT_FOUND;
|
|
goto cleanup;
|
|
}
|
|
|
|
SmbDereferenceObject((PSMB_OBJECT)pIf, SMB_REF_FIND);
|
|
|
|
SmbCfg.IPDeviceNumber--;
|
|
RemoveEntryList(&pIf->Linkage);
|
|
InsertTailList(&SmbCfg.PendingDeleteIPDeviceList, &pIf->Linkage);
|
|
SmbPrint(SMB_TRACE_PNP, ("Delete device %Z\n", &ucName));
|
|
SmbTrace(SMB_TRACE_PNP, ("Delete %Z", &ucName));
|
|
|
|
SmbDereferenceObject((PSMB_OBJECT)pIf, SMB_REF_CREATE);
|
|
|
|
cleanup:
|
|
if (ucName.Buffer) {
|
|
ExFreePool(ucName.Buffer);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbTdiRegister(
|
|
IN PSMB_DEVICE DeviceObject
|
|
)
|
|
{
|
|
UNICODE_STRING ExportName = { 0 };
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
status = STATUS_SUCCESS;
|
|
if (NULL == DeviceObject->DeviceRegistrationHandle) {
|
|
RtlInitUnicodeString(&ExportName, DD_SMB6_EXPORT_NAME);
|
|
status = TdiRegisterDeviceObject(&ExportName, &DeviceObject->DeviceRegistrationHandle);
|
|
SmbTrace(SMB_TRACE_PNP, ("TdiRegisterDeviceObject returns %!status!", status));
|
|
SmbPrint(SMB_TRACE_PNP, ("TdiRegisterDeviceObject returns 0x%08lx\n", status));
|
|
|
|
//
|
|
// Don't use SmbWakeupWorkerThread. This should be handled synchronously
|
|
//
|
|
if (SmbCfg.Tcp6Available) {
|
|
SmbReadTCPConf(SmbCfg.ParametersKey, &DeviceObject->Tcp6);
|
|
status = SmbSynchConnCache(&DeviceObject->Tcp6, FALSE);
|
|
SmbTrace(SMB_TRACE_PNP, ("SmbSynchConnCache (TCP6) returns %!status!", status));
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbSynchConnCache (TCP6) returns 0x%08lx\n", status));
|
|
}
|
|
|
|
if (SmbCfg.Tcp4Available) {
|
|
SmbReadTCPConf(SmbCfg.ParametersKey, &DeviceObject->Tcp4);
|
|
status = SmbSynchConnCache(&DeviceObject->Tcp4, FALSE);
|
|
SmbTrace(SMB_TRACE_PNP, ("SmbSynchConnCache (TCP4) returns %!status!", status));
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbSynchConnCache (TCP4) returns 0x%08lx\n", status));
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbTdiDeregister(
|
|
IN PSMB_DEVICE DeviceObject
|
|
)
|
|
{
|
|
HANDLE RegHandle;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
RegHandle = InterlockedExchangePointer(&DeviceObject->DeviceRegistrationHandle, NULL);
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbTdiDeregister: RegHandle = %p\n", RegHandle));
|
|
|
|
status = STATUS_SUCCESS;
|
|
if (RegHandle) {
|
|
status = TdiDeregisterDeviceObject(RegHandle);
|
|
SmbTrace(SMB_TRACE_PNP, ("TdiDeregisterDeviceObject returns %!status!", status));
|
|
SmbPrint(SMB_TRACE_PNP, ("TdiDeregisterDeviceObject returns 0x%08lx\n", status));
|
|
|
|
//
|
|
// Don't use SmbWakeupWorkerThread. This should be handled synchronously
|
|
//
|
|
if (SmbCfg.Tcp6Available) {
|
|
status = SmbSynchConnCache(&DeviceObject->Tcp6, TRUE);
|
|
SmbTrace(SMB_TRACE_PNP, ("SmbSynchConnCache (TCP6) returns %!status!", status));
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbSynchConnCache (TCP6) returns 0x%08lx\n", status));
|
|
}
|
|
|
|
if (SmbCfg.Tcp4Available) {
|
|
status = SmbSynchConnCache(&DeviceObject->Tcp4, TRUE);
|
|
SmbTrace(SMB_TRACE_PNP, ("SmbSynchConnCache (TCP4) returns %!status!", status));
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbSynchConnCache (TCP4) returns 0x%08lx\n", status));
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
GetMultiSZInfo(
|
|
WCHAR *str,
|
|
LONG *cnt_ret,
|
|
LONG *size_ret
|
|
)
|
|
{
|
|
LONG cnt, size, len;
|
|
WCHAR *p;
|
|
|
|
cnt = 0;
|
|
size = 0;
|
|
p = str;
|
|
while (*p) {
|
|
cnt ++;
|
|
SmbPrint(SMB_TRACE_PNP, ("%d. %ws\n", cnt, p));
|
|
SmbTrace(SMB_TRACE_PNP, ("%d. %ws", cnt, p));
|
|
len = wcslen(p) + 1;
|
|
p += len;
|
|
size += len;
|
|
}
|
|
size++;
|
|
|
|
SmbPrint(SMB_TRACE_PNP, ("Total number=%d, Total Length=%d\n", cnt, size));
|
|
SmbTrace(SMB_TRACE_PNP, ("Total number=%d, Total Length=%d", cnt, size));
|
|
|
|
if (NULL != cnt_ret) {
|
|
*cnt_ret = cnt;
|
|
}
|
|
if (NULL != size_ret) {
|
|
*size_ret = size;
|
|
}
|
|
}
|
|
|
|
PWSTR
|
|
DuplicateMultiSZString(
|
|
IN PWSTR str
|
|
)
|
|
{
|
|
LONG size;
|
|
PVOID buffer;
|
|
|
|
GetMultiSZInfo(str, NULL, &size);
|
|
if (0 == size) {
|
|
SmbPrint(SMB_TRACE_PNP, ("GetMultiSZInfo return error!!!\n"));
|
|
return NULL;
|
|
}
|
|
|
|
size *= sizeof(WCHAR);
|
|
buffer = ExAllocatePoolWithTag(NonPagedPool, size, '2BMS');
|
|
if (NULL == buffer) {
|
|
SmbPrint(SMB_TRACE_PNP, ("Cannot allocate %d bytes memory from NonPagedPool\n", size));
|
|
return NULL;
|
|
}
|
|
|
|
RtlCopyMemory(buffer, str, size);
|
|
return buffer;
|
|
}
|
|
|
|
PUNICODE_STRING
|
|
SeparateMultiSZ(
|
|
WCHAR *str,
|
|
LONG *num
|
|
)
|
|
{
|
|
PUNICODE_STRING uc_strs;
|
|
LONG i, cnt, size, len;
|
|
WCHAR *p;
|
|
PVOID *buffer;
|
|
UNICODE_STRING ucName;
|
|
|
|
PAGED_CODE();
|
|
|
|
GetMultiSZInfo(str, &cnt, &len);
|
|
if (cnt == 0 || len == 0) {
|
|
SmbPrint(SMB_TRACE_PNP, ("GetMultiSZInfo return error!!!\n"));
|
|
return NULL;
|
|
}
|
|
|
|
size = len * sizeof(WCHAR) + cnt * sizeof (UNICODE_STRING);
|
|
uc_strs = (PUNICODE_STRING)ExAllocatePoolWithTag(NonPagedPool, size, '1BMS');
|
|
if (NULL == uc_strs) {
|
|
SmbPrint(SMB_TRACE_PNP, ("Cannot allocate %d bytes memory from NonPagedPool\n", size));
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Make a uppercase copy of str
|
|
//
|
|
p = (WCHAR*)(uc_strs + cnt);
|
|
for (i = 0; i < len; i++) {
|
|
p[i] = RtlUpcaseUnicodeChar(str[i]);
|
|
}
|
|
|
|
p = (WCHAR*)(uc_strs + cnt);
|
|
for (i = 0; (i < cnt) && (*p); i++) {
|
|
RtlInitUnicodeString(&ucName, p);
|
|
p += (ucName.Length/sizeof(WCHAR)) + 1;
|
|
uc_strs[i] = ucName;
|
|
}
|
|
|
|
ASSERT (i == cnt);
|
|
if (NULL != num) {
|
|
*num = cnt;
|
|
}
|
|
return uc_strs;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbSetTcpInfo(
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ULONG Entity,
|
|
IN ULONG Class,
|
|
IN ULONG ToiId,
|
|
IN ULONG ToiType,
|
|
IN ULONG InfoBufferValue
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG BufferLength;
|
|
PTCP_REQUEST_SET_INFORMATION_EX TcpInfo;
|
|
TCPSocketOption *SockOption;
|
|
|
|
PAGED_CODE();
|
|
|
|
BufferLength = sizeof(TCP_REQUEST_SET_INFORMATION_EX) + sizeof(TCPSocketOption);
|
|
TcpInfo = (PTCP_REQUEST_SET_INFORMATION_EX)ExAllocatePoolWithTag(NonPagedPool, BufferLength, '2BMS');
|
|
if (NULL == TcpInfo) {
|
|
return (STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
RtlZeroMemory(TcpInfo, BufferLength);
|
|
SockOption = (TCPSocketOption *) (&TcpInfo->Buffer[0]);
|
|
|
|
TcpInfo->ID.toi_entity.tei_entity = Entity;
|
|
TcpInfo->ID.toi_entity.tei_instance = TL_INSTANCE;
|
|
TcpInfo->ID.toi_class = Class;
|
|
TcpInfo->BufferSize = sizeof (TCPSocketOption);
|
|
|
|
//
|
|
// Set the Configured values
|
|
//
|
|
TcpInfo->ID.toi_id = ToiId;
|
|
TcpInfo->ID.toi_type = ToiType;
|
|
SockOption->tso_value = InfoBufferValue;
|
|
|
|
status = SmbSendIoctl(
|
|
FileObject,
|
|
IOCTL_TCP_SET_INFORMATION_EX,
|
|
TcpInfo,
|
|
BufferLength,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
SmbPrint(SMB_TRACE_TCP, ("SmbSetTcpInfo: SetTcpInfo FAILed <0x%x>, Id=<0x%x>, Type=<0x%x>, Value=<0x%x>\n",
|
|
status, ToiId, ToiType, InfoBufferValue));
|
|
SmbTrace(SMB_TRACE_TCP, ("FAILed %!status!, Id=<0x%x>, Type=<0x%x>, Value=<0x%x>\n",
|
|
status, ToiId, ToiType, InfoBufferValue));
|
|
}
|
|
|
|
ExFreePool (TcpInfo);
|
|
|
|
return status;
|
|
}
|
|
|
|
#ifdef STANDALONE_SMB
|
|
#define NETBT_PREFIX L"\\DEVICE\\SMB_"
|
|
#else
|
|
#define NETBT_PREFIX L"\\DEVICE\\NETBT_"
|
|
#endif
|
|
#define DEVICE_PREFIX L"\\DEVICE\\"
|
|
|
|
NTSTATUS
|
|
SmbSetDeviceBindingInfo(
|
|
PSMB_DEVICE Device,
|
|
PNETBT_SMB_BIND_REQUEST SmbRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the binding information for one IPv4 device
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING ucName;
|
|
PSMB_TCP_DEVICE pIf;
|
|
KIRQL Irql;
|
|
ULONG Operation;
|
|
NTSTATUS status;
|
|
SHORT NbtPrefixSize, DevPrefixSize;
|
|
|
|
if (NULL == SmbRequest->pDeviceName) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
if (SmbRequest->PnPOpCode != TDI_PNP_OP_ADD && SmbRequest->PnPOpCode != TDI_PNP_OP_DEL) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
status = SmbUpcaseUnicodeStringNP(&ucName, SmbRequest->pDeviceName);
|
|
if (STATUS_SUCCESS != status) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Remove the NetBT prefix
|
|
//
|
|
NbtPrefixSize = wcslen(NETBT_PREFIX) * sizeof(WCHAR);
|
|
DevPrefixSize = wcslen(DEVICE_PREFIX) * sizeof(WCHAR);
|
|
ASSERT(DevPrefixSize < NbtPrefixSize);
|
|
if (RtlEqualMemory(ucName.Buffer, NETBT_PREFIX, NbtPrefixSize)) {
|
|
RtlMoveMemory((BYTE*)(ucName.Buffer) + DevPrefixSize,
|
|
(BYTE*)(ucName.Buffer) + NbtPrefixSize,
|
|
ucName.MaximumLength - NbtPrefixSize
|
|
);
|
|
ucName.Length -= NbtPrefixSize - DevPrefixSize;
|
|
}
|
|
|
|
SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
|
|
pIf = SmbFindAndReferenceInterface(&ucName);
|
|
SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
|
|
ExFreePool(ucName.Buffer);
|
|
|
|
if (NULL == pIf) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (SmbRequest->RequestType == SMB_CLIENT) {
|
|
pIf->EnableOutbound = (SmbRequest->PnPOpCode == TDI_PNP_OP_ADD);
|
|
SmbDereferenceObject((PSMB_OBJECT)pIf, SMB_REF_FIND);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Inbound
|
|
//
|
|
if (SmbRequest->PnPOpCode == TDI_PNP_OP_ADD) {
|
|
pIf->EnableInbound = TRUE;
|
|
Operation = AO_OPTION_ADD_IFLIST;
|
|
} else {
|
|
pIf->EnableInbound = FALSE;
|
|
Operation = AO_OPTION_DEL_IFLIST;
|
|
}
|
|
|
|
if (pIf->PrimaryIpAddress.sin_family == SMB_AF_INET &&
|
|
pIf->PrimaryIpAddress.ip4.sin4_addr != 0 &&
|
|
pIf->InterfaceIndex != INVALID_INTERFACE_INDEX) {
|
|
status = SmbSetTcpInfo (
|
|
Device->Tcp4.InboundAddressObject.AddressObject,
|
|
CO_TL_ENTITY,
|
|
INFO_CLASS_PROTOCOL,
|
|
Operation,
|
|
INFO_TYPE_ADDRESS_OBJECT,
|
|
pIf->InterfaceIndex
|
|
);
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbSetTcpInfo return 0x%08lx for %Z\n", status, &pIf->AdapterName));
|
|
SmbTrace(SMB_TRACE_PNP, ("SmbSetTcpInfo return %!status! for %Z", status, &pIf->AdapterName));
|
|
}
|
|
|
|
SmbDereferenceObject((PSMB_OBJECT)pIf, SMB_REF_FIND);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbBatchedSetBindingInfo(
|
|
PSMB_DEVICE Device,
|
|
ULONG RequestType,
|
|
PWSTR MultiSZBindList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set binding info for a set of IPv4 device
|
|
|
|
Note: the input is a list of IPv4 device which SMB device should be bound to.
|
|
The implication is that SMB should be unbound from the device which
|
|
is not in the input list!!!
|
|
We got to support this in order to maintain compatibility
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
LONG i, j, cnt, ip4device_cnt;
|
|
SHORT NbtPrefixSize, DevPrefixSize;
|
|
PUNICODE_STRING uc_strs;
|
|
KIRQL Irql;
|
|
PLIST_ENTRY entry;
|
|
PSMB_TCP_DEVICE pIf, *pIfSnapshot;
|
|
NTSTATUS status;
|
|
|
|
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
|
|
|
|
if (NULL == MultiSZBindList) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Separate the MutiSZ string
|
|
//
|
|
uc_strs = SeparateMultiSZ(MultiSZBindList, &cnt);
|
|
if (NULL == uc_strs) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Remove the NetBT prefix
|
|
//
|
|
NbtPrefixSize = wcslen(NETBT_PREFIX) * sizeof(WCHAR);
|
|
DevPrefixSize = wcslen(DEVICE_PREFIX) * sizeof(WCHAR);
|
|
ASSERT(DevPrefixSize < NbtPrefixSize);
|
|
|
|
SmbTrace(SMB_TRACE_PNP, ("Number of bindings: %d", cnt));
|
|
SmbPrint(SMB_TRACE_PNP, ("Number of bindings: %d\n", cnt));
|
|
for (i = 0; i < cnt; i++) {
|
|
if (RtlEqualMemory(uc_strs[i].Buffer, NETBT_PREFIX, NbtPrefixSize)) {
|
|
RtlMoveMemory((BYTE*)(uc_strs[i].Buffer) + DevPrefixSize,
|
|
(BYTE*)(uc_strs[i].Buffer) + NbtPrefixSize,
|
|
uc_strs[i].MaximumLength - NbtPrefixSize
|
|
);
|
|
uc_strs[i].Length -= NbtPrefixSize - DevPrefixSize;
|
|
}
|
|
SmbTrace(SMB_TRACE_PNP, ("\t%d. bind to %Z", i + 1, uc_strs + i));
|
|
SmbPrint(SMB_TRACE_PNP, ("\t%d. bind to %Z\n", i + 1, uc_strs + i));
|
|
}
|
|
|
|
//
|
|
// Handle the SMB_CLIENT request
|
|
//
|
|
if (RequestType == SMB_CLIENT) {
|
|
SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
|
|
entry = SmbCfg.IPDeviceList.Flink;
|
|
while(entry != &SmbCfg.IPDeviceList) {
|
|
pIf = CONTAINING_RECORD(entry, SMB_TCP_DEVICE, Linkage);
|
|
entry = entry->Flink;
|
|
|
|
pIf->EnableOutbound = FALSE;
|
|
for (i = 0; i < cnt; i++) {
|
|
if (pIf->AdapterName.Length == uc_strs[i].Length &&
|
|
RtlEqualMemory(pIf->AdapterName.Buffer, uc_strs[i].Buffer, uc_strs[i].Length)) {
|
|
|
|
pIf->EnableOutbound = TRUE;
|
|
SmbTrace(SMB_TRACE_PNP, ("Enable outbound on %Z", &pIf->AdapterName));
|
|
}
|
|
}
|
|
}
|
|
SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
|
|
|
|
ExFreePool(uc_strs);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ASSERT(RequestType == SMB_SERVER);
|
|
|
|
//
|
|
// A little bit more complex for server
|
|
// The linked list could be modified while calling into TCP because
|
|
// we cannot hold lock while calling other components.
|
|
//
|
|
|
|
//
|
|
// Make a snapshot and reference them
|
|
//
|
|
SMB_ACQUIRE_SPINLOCK(&SmbCfg, Irql);
|
|
ip4device_cnt = SmbCfg.IPAddressNumber;
|
|
if (ip4device_cnt == 0) {
|
|
SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
|
|
ExFreePool(uc_strs);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
pIfSnapshot = (PSMB_TCP_DEVICE*)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(PSMB_TCP_DEVICE)*ip4device_cnt,
|
|
SMB_TCP_DEVICE_POOL_TAG
|
|
);
|
|
if (NULL == pIfSnapshot) {
|
|
SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
|
|
ExFreePool(uc_strs);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
for (i = 0, entry = SmbCfg.IPDeviceList.Flink;
|
|
(i < ip4device_cnt) && entry != &SmbCfg.IPDeviceList;
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
pIf = CONTAINING_RECORD(entry, SMB_TCP_DEVICE, Linkage);
|
|
if (pIf->PrimaryIpAddress.sin_family == SMB_AF_INET &&
|
|
pIf->PrimaryIpAddress.ip4.sin4_addr != 0 &&
|
|
pIf->InterfaceIndex != INVALID_INTERFACE_INDEX) {
|
|
SmbReferenceObject((PSMB_OBJECT)pIf, SMB_REF_FIND);
|
|
pIfSnapshot[i] = pIf;
|
|
i++;
|
|
}
|
|
}
|
|
ASSERT (i <= ip4device_cnt);
|
|
ip4device_cnt = i;
|
|
SMB_RELEASE_SPINLOCK(&SmbCfg, Irql);
|
|
|
|
for (i = 0; i < ip4device_cnt; i++) {
|
|
pIf = pIfSnapshot[i];
|
|
|
|
pIf->EnableInbound = FALSE;
|
|
for (j = 0; j < cnt; j++) {
|
|
if (pIf->AdapterName.Length == uc_strs[j].Length &&
|
|
RtlEqualMemory(pIf->AdapterName.Buffer, uc_strs[j].Buffer, uc_strs[j].Length)) {
|
|
|
|
pIf->EnableInbound = TRUE;
|
|
SmbTrace(SMB_TRACE_PNP, ("Enable inbound on %Z", &pIf->AdapterName));
|
|
}
|
|
}
|
|
|
|
status = SmbSetTcpInfo (
|
|
Device->Tcp4.InboundAddressObject.AddressObject,
|
|
CO_TL_ENTITY,
|
|
INFO_CLASS_PROTOCOL,
|
|
pIf->EnableInbound? AO_OPTION_ADD_IFLIST: AO_OPTION_DEL_IFLIST,
|
|
INFO_TYPE_ADDRESS_OBJECT,
|
|
pIf->InterfaceIndex
|
|
);
|
|
SmbPrint(SMB_TRACE_PNP, ("SmbSetTcpInfo return 0x%08lx for %Z\n", status, &pIf->AdapterName));
|
|
SmbTrace(SMB_TRACE_PNP, ("SmbSetTcpInfo return %!status! for %Z", status, &pIf->AdapterName));
|
|
|
|
SmbDereferenceObject((PSMB_OBJECT)pIf, SMB_REF_FIND);
|
|
}
|
|
ExFreePool(uc_strs);
|
|
ExFreePool(pIfSnapshot);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbSetBindingInfo(
|
|
PSMB_DEVICE Device,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PNETBT_SMB_BIND_REQUEST SmbRequest;
|
|
NTSTATUS status;
|
|
PWSTR MultiSZBindList;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Irp->RequestorMode != KernelMode) {
|
|
return STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(NETBT_SMB_BIND_REQUEST)) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
SmbRequest = (PNETBT_SMB_BIND_REQUEST)Irp->AssociatedIrp.SystemBuffer;
|
|
if (SmbRequest->RequestType != SMB_CLIENT && SmbRequest->RequestType != SMB_SERVER) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (NULL == SmbRequest->MultiSZBindList) {
|
|
return SmbSetDeviceBindingInfo(Device, SmbRequest);
|
|
}
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceExclusiveLite(&SmbCfg.Resource, TRUE);
|
|
|
|
MultiSZBindList = DuplicateMultiSZString(SmbRequest->MultiSZBindList);
|
|
if (NULL != MultiSZBindList) {
|
|
|
|
//
|
|
// Update the binding list
|
|
//
|
|
if (SMB_CLIENT == SmbRequest->RequestType) {
|
|
if (Device->ClientBinding) {
|
|
ExFreePool(Device->ClientBinding);
|
|
}
|
|
Device->ClientBinding = MultiSZBindList;
|
|
} else if (SMB_SERVER == SmbRequest->RequestType) {
|
|
if (Device->ServerBinding) {
|
|
ExFreePool(Device->ServerBinding);
|
|
}
|
|
Device->ServerBinding = MultiSZBindList;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Out of resource is not severe error. Simply ignore it.
|
|
//
|
|
}
|
|
|
|
status = SmbBatchedSetBindingInfo(Device, SmbRequest->RequestType, SmbRequest->MultiSZBindList);
|
|
ExReleaseResourceLite(&SmbCfg.Resource);
|
|
KeLeaveCriticalRegion();
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbSetInboundIPv6Protection(
|
|
IN PSMB_DEVICE pDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine set the TCP/IPv6 listening protection level
|
|
IPv6 stack support 3 level of protection:
|
|
PROTECTION_LEVEL_RESTRICTED: intranet scenario
|
|
allow connection requests from local address only
|
|
PROTECTION_LEVEL_DEFAULT: default level
|
|
PROTECTION_LEVEL_UNRESTRICTED: for peer to peer connection
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KIRQL Irql = 0;
|
|
PFILE_OBJECT pIPv6AO = NULL;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
ULONG uIPv6ProtectionLevel = 0;
|
|
|
|
SMB_ACQUIRE_SPINLOCK(pDeviceObject, Irql);
|
|
pIPv6AO = pDeviceObject->Tcp6.InboundAddressObject.AddressObject;
|
|
if (pIPv6AO == NULL) {
|
|
SMB_RELEASE_SPINLOCK(pDeviceObject, Irql);
|
|
goto error;
|
|
}
|
|
ObReferenceObject(pIPv6AO);
|
|
SMB_RELEASE_SPINLOCK(pDeviceObject, Irql);
|
|
|
|
uIPv6ProtectionLevel = SmbCfg.uIPv6Protection;
|
|
|
|
ntStatus = SmbSetTcpInfo (
|
|
pIPv6AO,
|
|
CL_TL_ENTITY,
|
|
INFO_CLASS_PROTOCOL,
|
|
AO_OPTION_PROTECT,
|
|
INFO_TYPE_ADDRESS_OBJECT,
|
|
uIPv6ProtectionLevel
|
|
);
|
|
ObDereferenceObject(pIPv6AO);
|
|
SmbTrace(SMB_TRACE_PNP, ("IPv6Protection Level = %d: %!status!", uIPv6ProtectionLevel, ntStatus));
|
|
|
|
error:
|
|
return ntStatus;
|
|
}
|
|
|