Leaked source code of windows server 2003
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

/*++
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;
}