mirror of https://github.com/lianthony/NT4.0
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.
865 lines
22 KiB
865 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
info.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code which performs the following TDI services:
|
|
|
|
o TdiQueryInformation
|
|
o TdiSetInformation
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "st.h"
|
|
|
|
|
|
//
|
|
// Useful macro to obtain the total length of an MDL chain.
|
|
//
|
|
|
|
#define StGetMdlChainLength(Mdl, Length) { \
|
|
PMDL _Mdl = (Mdl); \
|
|
*(Length) = 0; \
|
|
while (_Mdl) { \
|
|
*(Length) += MmGetMdlByteCount(_Mdl); \
|
|
_Mdl = _Mdl->Next; \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// Local functions used to satisfy various requests.
|
|
//
|
|
|
|
VOID
|
|
StStoreProviderStatistics(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PTDI_PROVIDER_STATISTICS ProviderStatistics
|
|
);
|
|
|
|
VOID
|
|
StStoreAdapterStatus(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PUCHAR SourceRouting,
|
|
IN UINT SourceRoutingLength,
|
|
IN PVOID StatusBuffer
|
|
);
|
|
|
|
VOID
|
|
StStoreNameBuffers(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferLength,
|
|
IN ULONG NamesToSkip,
|
|
OUT PULONG NamesWritten,
|
|
OUT PULONG TotalNameCount OPTIONAL,
|
|
OUT PBOOLEAN Truncated
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
StTdiQueryInformation(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the TdiQueryInformation request for the transport
|
|
provider.
|
|
|
|
Arguments:
|
|
|
|
Irp - the Irp for the requested operation.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PVOID adapterStatus;
|
|
PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
|
|
PTA_NETBIOS_ADDRESS broadcastAddress;
|
|
PTDI_PROVIDER_STATISTICS ProviderStatistics;
|
|
PTDI_CONNECTION_INFO ConnectionInfo;
|
|
ULONG TargetBufferLength;
|
|
LARGE_INTEGER timeout = {0,0};
|
|
PTP_CONNECTION Connection;
|
|
PTP_ADDRESS_FILE AddressFile;
|
|
PTP_ADDRESS Address;
|
|
struct {
|
|
ULONG ActivityCount;
|
|
TA_NETBIOS_ADDRESS TaAddressBuffer;
|
|
} AddressInfo;
|
|
ULONG NamesWritten, TotalNameCount, BytesWritten;
|
|
PLIST_ENTRY p;
|
|
KIRQL oldirql;
|
|
BOOLEAN Truncated;
|
|
BOOLEAN UsedConnection;
|
|
|
|
//
|
|
// what type of status do we want?
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&irpSp->Parameters;
|
|
|
|
switch (query->QueryType) {
|
|
|
|
case TDI_QUERY_CONNECTION_INFO:
|
|
|
|
//
|
|
// Connection info is queried on a connection,
|
|
// verify this.
|
|
//
|
|
|
|
Connection = irpSp->FileObject->FsContext;
|
|
|
|
status = StVerifyConnectionObject (Connection);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
|
|
ConnectionInfo = ExAllocatePool (
|
|
NonPagedPool,
|
|
sizeof (TDI_CONNECTION_INFO));
|
|
|
|
if (ConnectionInfo == NULL) {
|
|
|
|
PANIC ("StQueryInfo: Cannot allocate connection info!\n");
|
|
StWriteResourceErrorLog (DeviceContext, sizeof(TDI_CONNECTION_INFO), 6);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else if ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
|
|
|
|
status = Connection->Status;
|
|
ExFreePool (ConnectionInfo);
|
|
|
|
} else if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
|
|
|
|
status = STATUS_INVALID_CONNECTION;
|
|
ExFreePool (ConnectionInfo);
|
|
|
|
} else {
|
|
|
|
RtlZeroMemory ((PVOID)ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
|
|
|
|
//
|
|
// Fill in connection information here.
|
|
//
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
(PVOID)ConnectionInfo,
|
|
0L,
|
|
sizeof(TDI_CONNECTION_INFO),
|
|
Irp->MdlAddress,
|
|
0,
|
|
&(Irp->IoStatus.Information));
|
|
|
|
ExFreePool (ConnectionInfo);
|
|
}
|
|
|
|
StDereferenceConnection ("query connection info", Connection);
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_ADDRESS_INFO:
|
|
|
|
//
|
|
// Information about an address, can also be queried on a
|
|
// connection object to get information about its address.
|
|
//
|
|
|
|
if (irpSp->FileObject->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
|
|
|
|
AddressFile = irpSp->FileObject->FsContext;
|
|
|
|
status = StVerifyAddressObject(AddressFile);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
|
|
UsedConnection = FALSE;
|
|
|
|
} else if (irpSp->FileObject->FsContext2 == (PVOID)TDI_CONNECTION_FILE) {
|
|
|
|
Connection = irpSp->FileObject->FsContext;
|
|
|
|
status = StVerifyConnectionObject (Connection);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
|
|
AddressFile = Connection->AddressFile;
|
|
|
|
UsedConnection = TRUE;
|
|
|
|
} else {
|
|
|
|
return STATUS_INVALID_ADDRESS;
|
|
|
|
}
|
|
|
|
Address = AddressFile->Address;
|
|
|
|
TdiBuildNetbiosAddress(
|
|
Address->NetworkName->NetbiosName,
|
|
(BOOLEAN)(Address->Flags & ADDRESS_FLAGS_GROUP ? TRUE : FALSE),
|
|
&AddressInfo.TaAddressBuffer);
|
|
|
|
//
|
|
// Count the active addresses.
|
|
//
|
|
|
|
AddressInfo.ActivityCount = 0;
|
|
|
|
ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
|
|
|
|
for (p = Address->AddressFileDatabase.Flink;
|
|
p != &Address->AddressFileDatabase;
|
|
p = p->Flink) {
|
|
++AddressInfo.ActivityCount;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
&AddressInfo,
|
|
0,
|
|
sizeof(ULONG) + sizeof(TA_NETBIOS_ADDRESS),
|
|
Irp->MdlAddress,
|
|
0,
|
|
&Irp->IoStatus.Information);
|
|
|
|
if (UsedConnection) {
|
|
|
|
StDereferenceConnection ("query address info", Connection);
|
|
|
|
} else {
|
|
|
|
StDereferenceAddress ("query address info", Address);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_BROADCAST_ADDRESS:
|
|
|
|
//
|
|
// for this provider, the broadcast address is a zero byte name,
|
|
// contained in a Transport address structure.
|
|
//
|
|
|
|
broadcastAddress = ExAllocatePool (
|
|
NonPagedPool,
|
|
sizeof (TA_NETBIOS_ADDRESS));
|
|
if (broadcastAddress == NULL) {
|
|
PANIC ("StQueryInfo: Cannot allocate broadcast address!\n");
|
|
StWriteResourceErrorLog (DeviceContext, sizeof(TA_NETBIOS_ADDRESS), 2);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
|
|
broadcastAddress->TAAddressCount = 1;
|
|
broadcastAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
broadcastAddress->Address[0].AddressLength = 0;
|
|
|
|
Irp->IoStatus.Information =
|
|
sizeof (broadcastAddress->TAAddressCount) +
|
|
sizeof (broadcastAddress->Address[0].AddressType) +
|
|
sizeof (broadcastAddress->Address[0].AddressLength);
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
(PVOID)broadcastAddress,
|
|
0L,
|
|
Irp->IoStatus.Information,
|
|
Irp->MdlAddress,
|
|
0,
|
|
&(Irp->IoStatus.Information));
|
|
|
|
ExFreePool (broadcastAddress);
|
|
}
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_PROVIDER_INFO:
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
&(DeviceContext->Information),
|
|
0,
|
|
sizeof (TDI_PROVIDER_INFO),
|
|
Irp->MdlAddress,
|
|
0,
|
|
&Irp->IoStatus.Information);
|
|
break;
|
|
|
|
case TDI_QUERY_PROVIDER_STATISTICS:
|
|
|
|
StGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
|
|
|
|
if (TargetBufferLength < sizeof(TDI_PROVIDER_STATISTICS) + ((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS))) {
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
|
|
} else {
|
|
|
|
ProviderStatistics = ExAllocatePool(
|
|
NonPagedPool,
|
|
sizeof(TDI_PROVIDER_STATISTICS) +
|
|
((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)));
|
|
|
|
if (ProviderStatistics == NULL) {
|
|
|
|
PANIC ("StQueryInfo: Cannot allocate provider statistics!\n");
|
|
StWriteResourceErrorLog (DeviceContext, sizeof(TDI_PROVIDER_STATISTICS), 7);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
StStoreProviderStatistics (DeviceContext, ProviderStatistics);
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
(PVOID)ProviderStatistics,
|
|
0L,
|
|
sizeof(TDI_PROVIDER_STATISTICS) +
|
|
((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)),
|
|
Irp->MdlAddress,
|
|
0,
|
|
&(Irp->IoStatus.Information));
|
|
|
|
ExFreePool (ProviderStatistics);
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_SESSION_STATUS:
|
|
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case TDI_QUERY_ADAPTER_STATUS:
|
|
|
|
StGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
|
|
|
|
//
|
|
// Determine if this is a local or remote query. It is
|
|
// local if there is no remote address specific at all,
|
|
// or if it is equal to our reserved address.
|
|
//
|
|
|
|
if ((query->RequestConnectionInformation != NULL) &&
|
|
(!RtlEqualMemory(
|
|
((PTA_NETBIOS_ADDRESS)(query->RequestConnectionInformation->RemoteAddress))->
|
|
Address[0].Address[0].NetbiosName,
|
|
DeviceContext->ReservedNetBIOSAddress,
|
|
NETBIOS_NAME_LENGTH))) {
|
|
|
|
//
|
|
// Remote, not supported here.
|
|
//
|
|
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Local.
|
|
//
|
|
|
|
adapterStatus = ExAllocatePool (
|
|
NonPagedPool,
|
|
TargetBufferLength);
|
|
|
|
if (adapterStatus == NULL) {
|
|
PANIC("StQueryInfo: PANIC! Could not allocate adapter status buffer\n");
|
|
StWriteResourceErrorLog (DeviceContext, TargetBufferLength, 3);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
StStoreAdapterStatus (
|
|
DeviceContext,
|
|
NULL,
|
|
0,
|
|
adapterStatus);
|
|
|
|
StStoreNameBuffers (
|
|
DeviceContext,
|
|
(PUCHAR)adapterStatus + sizeof(ADAPTER_STATUS),
|
|
TargetBufferLength - sizeof(ADAPTER_STATUS),
|
|
0,
|
|
&NamesWritten,
|
|
&TotalNameCount,
|
|
&Truncated);
|
|
|
|
((PADAPTER_STATUS)adapterStatus)->name_count = (WORD)TotalNameCount;
|
|
|
|
BytesWritten = sizeof(ADAPTER_STATUS) + (NamesWritten * sizeof(NAME_BUFFER));
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
adapterStatus,
|
|
0,
|
|
BytesWritten,
|
|
Irp->MdlAddress,
|
|
0,
|
|
&Irp->IoStatus.Information);
|
|
|
|
if (Truncated) {
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
ExFreePool (adapterStatus);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_FIND_NAME:
|
|
|
|
//
|
|
// Find name, not supported here.
|
|
//
|
|
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
default:
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
|
|
} /* StTdiQueryInformation */
|
|
|
|
//
|
|
// Quick macros, assumes DeviceContext and ProviderStatistics exist.
|
|
//
|
|
|
|
#define STORE_RESOURCE_STATS_1(_ResourceNum,_ResourceId,_ResourceName) \
|
|
{ \
|
|
PTDI_PROVIDER_RESOURCE_STATS RStats = &ProviderStatistics->ResourceStats[_ResourceNum]; \
|
|
RStats->ResourceId = (_ResourceId); \
|
|
RStats->MaximumResourceUsed = DeviceContext->_ResourceName ## MaxInUse; \
|
|
if (DeviceContext->_ResourceName ## Samples > 0) { \
|
|
RStats->AverageResourceUsed = DeviceContext->_ResourceName ## Total / DeviceContext->_ResourceName ## Samples; \
|
|
} else { \
|
|
RStats->AverageResourceUsed = 0; \
|
|
} \
|
|
RStats->ResourceExhausted = DeviceContext->_ResourceName ## Exhausted; \
|
|
}
|
|
|
|
#define STORE_RESOURCE_STATS_2(_ResourceNum,_ResourceId,_ResourceName) \
|
|
{ \
|
|
PTDI_PROVIDER_RESOURCE_STATS RStats = &ProviderStatistics->ResourceStats[_ResourceNum]; \
|
|
RStats->ResourceId = (_ResourceId); \
|
|
RStats->MaximumResourceUsed = DeviceContext->_ResourceName ## Allocated; \
|
|
RStats->AverageResourceUsed = DeviceContext->_ResourceName ## Allocated; \
|
|
RStats->ResourceExhausted = DeviceContext->_ResourceName ## Exhausted; \
|
|
}
|
|
|
|
|
|
VOID
|
|
StStoreProviderStatistics(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PTDI_PROVIDER_STATISTICS ProviderStatistics
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes the TDI_PROVIDER_STATISTICS structure
|
|
from the device context into ProviderStatistics.
|
|
|
|
Arguments:
|
|
|
|
DeviceContext - a pointer to the device context.
|
|
|
|
ProviderStatistics - The buffer that holds the result. It is assumed
|
|
that it is long enough.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ProviderStatistics->Version = 0x0100;
|
|
|
|
//
|
|
// Copy all the statistics from OpenConnections to WastedSpace
|
|
// Packets in one move.
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
(PVOID)&(ProviderStatistics->OpenConnections),
|
|
(PVOID)&(DeviceContext->OpenConnections),
|
|
sizeof(TDI_PROVIDER_STATISTICS));
|
|
|
|
//
|
|
// Copy the resource statistics.
|
|
//
|
|
|
|
ProviderStatistics->NumberOfResources = ST_TDI_RESOURCES;
|
|
|
|
STORE_RESOURCE_STATS_1 (0, 12, Address);
|
|
STORE_RESOURCE_STATS_1 (1, 13, AddressFile);
|
|
STORE_RESOURCE_STATS_1 (2, 14, Connection);
|
|
STORE_RESOURCE_STATS_1 (3, 15, Request);
|
|
|
|
STORE_RESOURCE_STATS_2 (4, 22, Packet);
|
|
STORE_RESOURCE_STATS_2 (5, 23, ReceivePacket);
|
|
STORE_RESOURCE_STATS_2 (6, 24, ReceiveBuffer);
|
|
|
|
} /* StStoreProviderStatistics */
|
|
|
|
|
|
VOID
|
|
StStoreAdapterStatus(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PUCHAR SourceRouting,
|
|
IN UINT SourceRoutingLength,
|
|
IN PVOID StatusBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes the ADAPTER_STATUS structure for the
|
|
device context into StatusBuffer. The name_count field is
|
|
initialized to zero; StStoreNameBuffers is used to write
|
|
name buffers.
|
|
|
|
Arguments:
|
|
|
|
DeviceContext - a pointer to the device context.
|
|
|
|
SourceRouting - If this is a remote request, the source
|
|
routing information from the frame.
|
|
|
|
SourceRoutingLength - The length of SourceRouting.
|
|
|
|
StatusBuffer - The buffer that holds the result. It is assumed
|
|
that it is at least sizeof(ADAPTER_STATUS) bytes long.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PADAPTER_STATUS AdapterStatus = (PADAPTER_STATUS)StatusBuffer;
|
|
UINT MaxUserData;
|
|
|
|
RtlZeroMemory ((PVOID)AdapterStatus, sizeof(ADAPTER_STATUS));
|
|
|
|
RtlCopyMemory (AdapterStatus->adapter_address, DeviceContext->LocalAddress.Address, 6);
|
|
AdapterStatus->rev_major = 0x03;
|
|
|
|
switch (DeviceContext->MacInfo.MediumType) {
|
|
case NdisMedium802_5: AdapterStatus->adapter_type = 0xff; break;
|
|
default: AdapterStatus->adapter_type = 0xfe; break;
|
|
}
|
|
|
|
AdapterStatus->frmr_recv = 0;
|
|
AdapterStatus->frmr_xmit = 0;
|
|
|
|
AdapterStatus->recv_buff_unavail = (WORD)(DeviceContext->ReceivePacketExhausted + DeviceContext->ReceiveBufferExhausted);
|
|
AdapterStatus->xmit_buf_unavail = (WORD)DeviceContext->PacketExhausted;
|
|
|
|
AdapterStatus->xmit_success = (WORD)(DeviceContext->IFramesSent - DeviceContext->IFramesResent);
|
|
AdapterStatus->recv_success = (WORD)DeviceContext->IFramesReceived;
|
|
AdapterStatus->iframe_recv_err = (WORD)DeviceContext->IFramesRejected;
|
|
AdapterStatus->iframe_xmit_err = (WORD)DeviceContext->IFramesResent;
|
|
|
|
AdapterStatus->t1_timeouts = 0;
|
|
AdapterStatus->ti_timeouts = 0;
|
|
AdapterStatus->xmit_aborts = 0;
|
|
|
|
|
|
AdapterStatus->free_ncbs = 0xffff;
|
|
AdapterStatus->max_cfg_ncbs = 0xffff;
|
|
AdapterStatus->max_ncbs = 0xffff;
|
|
AdapterStatus->pending_sess = (WORD)DeviceContext->OpenConnections;
|
|
AdapterStatus->max_cfg_sess = 0xffff;
|
|
AdapterStatus->max_sess = 0xffff;
|
|
|
|
|
|
MacReturnMaxDataSize(
|
|
&DeviceContext->MacInfo,
|
|
SourceRouting,
|
|
SourceRoutingLength,
|
|
DeviceContext->MaxSendPacketSize,
|
|
&MaxUserData);
|
|
|
|
AdapterStatus->max_dgram_size = (WORD)(MaxUserData - sizeof(ST_HEADER));
|
|
AdapterStatus->max_sess_pkt_size = (WORD)(MaxUserData - sizeof(ST_HEADER));
|
|
|
|
return;
|
|
|
|
} /* StStoreAdapterStatus */
|
|
|
|
|
|
VOID
|
|
StStoreNameBuffers(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferLength,
|
|
IN ULONG NamesToSkip,
|
|
OUT PULONG NamesWritten,
|
|
OUT PULONG TotalNameCount OPTIONAL,
|
|
OUT PBOOLEAN Truncated
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes NAME_BUFFER structures for the
|
|
device context into NameBuffer. It can skip a specified
|
|
number of names at the beginning, and returns the number
|
|
of names written into NameBuffer. If a name will only
|
|
partially fit, it is not written.
|
|
|
|
Arguments:
|
|
|
|
DeviceContext - a pointer to the device context.
|
|
|
|
NameBuffer - The buffer to write the names into.
|
|
|
|
NameBufferLength - The length of NameBuffer.
|
|
|
|
NamesToSkip - The number of names to skip.
|
|
|
|
NamesWritten - Returns the number of names written.
|
|
|
|
TotalNameCount - Returns the total number of names available,
|
|
if specified.
|
|
|
|
Truncated - More names are available than were written.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG NameCount = 0;
|
|
ULONG BytesWritten = 0;
|
|
KIRQL oldirql;
|
|
PLIST_ENTRY p;
|
|
PNAME_BUFFER NameBuffer = (PNAME_BUFFER)Buffer;
|
|
PTP_ADDRESS address;
|
|
|
|
|
|
//
|
|
// Spin through the address list for this device context.
|
|
//
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
|
|
|
|
p = DeviceContext->AddressDatabase.Flink;
|
|
|
|
for (p = DeviceContext->AddressDatabase.Flink;
|
|
p != &DeviceContext->AddressDatabase;
|
|
p = p->Flink) {
|
|
|
|
address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
|
|
|
|
//
|
|
// Ignore addresses that are shutting down.
|
|
//
|
|
|
|
if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Ignore the broadcast address.
|
|
//
|
|
|
|
if (address->NetworkName == NULL) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Ignore the reserved address.
|
|
//
|
|
|
|
if ((address->NetworkName->NetbiosName[0] == 0) &&
|
|
(RtlEqualMemory(
|
|
address->NetworkName->NetbiosName,
|
|
DeviceContext->ReservedNetBIOSAddress,
|
|
NETBIOS_NAME_LENGTH))) {
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check if we are still skipping.
|
|
//
|
|
|
|
if (NameCount < NamesToSkip) {
|
|
++NameCount;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Make sure we still have room.
|
|
//
|
|
|
|
if (BytesWritten + sizeof(NAME_BUFFER) > BufferLength) {
|
|
break;
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
NameBuffer->name,
|
|
address->NetworkName->NetbiosName,
|
|
NETBIOS_NAME_LENGTH);
|
|
|
|
++NameCount;
|
|
NameBuffer->name_num = (UCHAR)NameCount;
|
|
|
|
NameBuffer->name_flags = REGISTERED;
|
|
if (address->Flags & ADDRESS_FLAGS_GROUP) {
|
|
NameBuffer->name_flags |= GROUP_NAME;
|
|
}
|
|
|
|
// BUGBUG: name_flags should be done more accurately.
|
|
|
|
BytesWritten += sizeof(NAME_BUFFER);
|
|
++NameBuffer;
|
|
|
|
}
|
|
|
|
*NamesWritten = NameBuffer - (PNAME_BUFFER)Buffer;
|
|
|
|
if (p == &DeviceContext->AddressDatabase) {
|
|
|
|
*Truncated = FALSE;
|
|
if (ARGUMENT_PRESENT(TotalNameCount)) {
|
|
*TotalNameCount = NameCount;
|
|
}
|
|
|
|
} else {
|
|
|
|
*Truncated = TRUE;
|
|
|
|
//
|
|
// If requested, continue through the list and count
|
|
// all the addresses.
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT(TotalNameCount)) {
|
|
|
|
for ( ;
|
|
p != &DeviceContext->AddressDatabase;
|
|
p = p->Flink) {
|
|
|
|
address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
|
|
|
|
//
|
|
// Ignore addresses that are shutting down.
|
|
//
|
|
|
|
if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Ignore the broadcast address.
|
|
//
|
|
|
|
if (address->NetworkName == NULL) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Ignore the reserved address, since we count it no matter what.
|
|
//
|
|
|
|
if ((address->NetworkName->NetbiosName[0] == 0) &&
|
|
(RtlEqualMemory(
|
|
address->NetworkName->NetbiosName,
|
|
DeviceContext->ReservedNetBIOSAddress,
|
|
NETBIOS_NAME_LENGTH))) {
|
|
|
|
continue;
|
|
}
|
|
|
|
++NameCount;
|
|
|
|
}
|
|
|
|
*TotalNameCount = NameCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
return;
|
|
|
|
} /* StStoreNameBuffers */
|
|
|
|
|
|
NTSTATUS
|
|
StTdiSetInformation(
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the TdiSetInformation request for the transport
|
|
provider.
|
|
|
|
Arguments:
|
|
|
|
Irp - the Irp for the requested operation.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER (Irp);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
} /* StTdiQueryInformation */
|
|
|