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.
3517 lines
98 KiB
3517 lines
98 KiB
/*++
|
|
|
|
Copyright (c) 1989, 1990, 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
info.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code which performs the following TDI services:
|
|
|
|
o TdiQueryInformation
|
|
o TdiSetInformation
|
|
|
|
Author:
|
|
|
|
David Beaver (dbeaver) 1-July-1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
//
|
|
// Only the following routine is active in this module. All is is commented
|
|
// out waiting for the definition of Get/Set info in TDI version 2.
|
|
//
|
|
|
|
//
|
|
// Useful macro to obtain the total length of an MDL chain.
|
|
//
|
|
|
|
#define NbfGetMdlChainLength(Mdl, Length) { \
|
|
PMDL _Mdl = (Mdl); \
|
|
*(Length) = 0; \
|
|
while (_Mdl) { \
|
|
*(Length) += MmGetMdlByteCount(_Mdl); \
|
|
_Mdl = _Mdl->Next; \
|
|
} \
|
|
}
|
|
|
|
|
|
//
|
|
// Local functions used to satisfy various requests.
|
|
//
|
|
|
|
VOID
|
|
NbfStoreProviderStatistics(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PTDI_PROVIDER_STATISTICS ProviderStatistics
|
|
);
|
|
|
|
VOID
|
|
NbfStoreAdapterStatus(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PUCHAR SourceRouting,
|
|
IN UINT SourceRoutingLength,
|
|
IN PVOID StatusBuffer
|
|
);
|
|
|
|
VOID
|
|
NbfStoreNameBuffers(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferLength,
|
|
IN ULONG NamesToSkip,
|
|
OUT PULONG NamesWritten,
|
|
OUT PULONG TotalNameCount OPTIONAL,
|
|
OUT PBOOLEAN Truncated
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
NbfTdiQueryInformation(
|
|
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;
|
|
PFIND_NAME_HEADER FindNameHeader;
|
|
LARGE_INTEGER timeout = {0,0};
|
|
PTP_REQUEST tpRequest;
|
|
PTP_CONNECTION Connection;
|
|
PTP_ADDRESS_FILE AddressFile;
|
|
PTP_ADDRESS Address;
|
|
ULONG NamesWritten, TotalNameCount, BytesWritten;
|
|
BOOLEAN Truncated;
|
|
BOOLEAN RemoteAdapterStatus;
|
|
TDI_ADDRESS_NETBIOS * RemoteAddress;
|
|
struct {
|
|
ULONG ActivityCount;
|
|
TA_NETBIOS_ADDRESS TaAddressBuffer;
|
|
} AddressInfo;
|
|
PTRANSPORT_ADDRESS TaAddress;
|
|
TDI_DATAGRAM_INFO DatagramInfo;
|
|
BOOLEAN UsedConnection;
|
|
PLIST_ENTRY p;
|
|
KIRQL oldirql;
|
|
ULONG BytesCopied;
|
|
|
|
//
|
|
// what type of status do we want?
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&irpSp->Parameters;
|
|
|
|
switch (query->QueryType) {
|
|
|
|
#if 0
|
|
case 0x12345678:
|
|
|
|
{
|
|
typedef struct _NBF_CONNECTION_STATUS {
|
|
UCHAR LocalName[16];
|
|
UCHAR RemoteName[16];
|
|
BOOLEAN SendActive;
|
|
BOOLEAN ReceiveQueued;
|
|
BOOLEAN ReceiveActive;
|
|
BOOLEAN ReceiveWakeUp;
|
|
ULONG Flags;
|
|
ULONG Flags2;
|
|
} NBF_CONNECTION_STATUS, *PNBF_CONNECTION_STATUS;
|
|
|
|
PNBF_CONNECTION_STATUS CurStatus;
|
|
ULONG TotalStatus;
|
|
ULONG AllowedStatus;
|
|
PLIST_ENRY q;
|
|
|
|
CurStatus = MmGetSystemAddressForMdl (Irp->MdlAddress);
|
|
TotalStatus = 0;
|
|
AllowedStatus = MmGetMdlByteCount (Irp->MdlAddress) / sizeof(NBF_CONNECTION_STATUS);
|
|
|
|
for (p = DeviceContext->AddressDatabase.Flink;
|
|
p != &DeviceContext->AddressDatabase;
|
|
p = p->Flink) {
|
|
|
|
Address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
|
|
|
|
if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
|
|
continue;
|
|
}
|
|
|
|
for (q = Address->ConnectionDatabase.Flink;
|
|
q != &Address->ConnectionDatabase;
|
|
q = q->Flink) {
|
|
|
|
Connection = CONTAINING_RECORD (q, TP_CONNECTION, AddressList);
|
|
|
|
if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (TotalStatus >= AllowedStatus) {
|
|
continue;
|
|
}
|
|
|
|
RtlMoveMemory (CurStatus->LocalName, Address->NetworkName->NetbiosName, 16);
|
|
RtlMoveMemory (CurStatus->RemoteName, Connection->RemoteName, 16);
|
|
|
|
CurStatus->Flags = Connection->Flags;
|
|
CurStatus->Flags2 = Connection->Flags2;
|
|
CurStatus->SendActive = (BOOLEAN)(!IsListEmpty(&Connection->SendQueue));
|
|
CurStatus->ReceiveQueued = (BOOLEAN)(!IsListEmpty(&Connection->ReceiveQueue));
|
|
CurStatus->ReceiveActive = (BOOLEAN)((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0);
|
|
CurStatus->ReceiveWakeUp = (BOOLEAN)((Connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) != 0);
|
|
|
|
++CurStatus;
|
|
++TotalStatus;
|
|
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Information = TotalStatus * sizeof(NBF_CONNECTION_STATUS);
|
|
status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
|
|
case TDI_QUERY_CONNECTION_INFO:
|
|
|
|
//
|
|
// Connection info is queried on a connection,
|
|
// verify this.
|
|
//
|
|
|
|
if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
|
|
return STATUS_INVALID_CONNECTION;
|
|
}
|
|
|
|
Connection = irpSp->FileObject->FsContext;
|
|
|
|
status = NbfVerifyConnectionObject (Connection);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
#if DBG
|
|
NbfPrint2 ("TdiQueryInfo: Invalid Connection %lx Irp %lx\n", Connection, Irp);
|
|
#endif
|
|
return status;
|
|
}
|
|
|
|
ConnectionInfo = ExAllocatePoolWithTag (
|
|
NonPagedPool,
|
|
sizeof (TDI_CONNECTION_INFO),
|
|
NBF_MEM_TAG_TDI_CONNECTION_INFO);
|
|
|
|
if (ConnectionInfo == NULL) {
|
|
|
|
PANIC ("NbfQueryInfo: Cannot allocate connection info!\n");
|
|
NbfWriteResourceErrorLog(
|
|
DeviceContext,
|
|
EVENT_TRANSPORT_RESOURCE_POOL,
|
|
6,
|
|
sizeof(TDI_CONNECTION_INFO),
|
|
0);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
|
|
|
|
status = STATUS_INVALID_CONNECTION;
|
|
ExFreePool (ConnectionInfo);
|
|
|
|
} else {
|
|
|
|
PTP_LINK Link = Connection->Link;
|
|
|
|
RtlZeroMemory ((PVOID)ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
|
|
|
|
|
|
//
|
|
// Get link delay and throughput.
|
|
//
|
|
|
|
if (Link->Delay == 0xffffffff) {
|
|
|
|
//
|
|
// If delay is not known, assume 0.
|
|
//
|
|
|
|
ConnectionInfo->Delay.HighPart = 0;
|
|
ConnectionInfo->Delay.LowPart = 0;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Copy the delay as an NT relative time.
|
|
//
|
|
|
|
ConnectionInfo->Delay.HighPart = -1L;
|
|
ConnectionInfo->Delay.LowPart = (ULONG)-((LONG)(Link->Delay));
|
|
|
|
}
|
|
|
|
if (DeviceContext->MacInfo.MediumAsync) {
|
|
|
|
ULONG PacketsSent;
|
|
ULONG PacketsResent;
|
|
ULONG MultiplyFactor;
|
|
|
|
//
|
|
// Calculate the packets sent and resent since the
|
|
// last time the throughput was queried.
|
|
//
|
|
|
|
PacketsSent = Link->PacketsSent - Connection->LastPacketsSent;
|
|
PacketsResent = Link->PacketsResent - Connection->LastPacketsResent;
|
|
|
|
//
|
|
// Save these for next time.
|
|
//
|
|
|
|
Connection->LastPacketsSent = Link->PacketsSent;
|
|
Connection->LastPacketsResent = Link->PacketsResent;
|
|
|
|
//
|
|
// To convert exactly from 100 bits-per-second to
|
|
// bytes-per-second, we need to multiply by 12.5.
|
|
// Using lower numbers will give worse throughput.
|
|
// If there have been no errors we use 12, if there
|
|
// have been 20% or more errors we use 1, and in
|
|
// between we subtract 11 * (error%/20%) from 12
|
|
// and use that.
|
|
//
|
|
|
|
if (PacketsResent == 0 || PacketsSent <= 10) {
|
|
|
|
MultiplyFactor = 12;
|
|
|
|
} else if ((PacketsSent / PacketsResent) <= 5) {
|
|
|
|
MultiplyFactor = 1;
|
|
|
|
} else {
|
|
|
|
//
|
|
// error%/20% is error%/(1/5), which is 5*error%,
|
|
// which is 5 * (resent/send).
|
|
//
|
|
|
|
ASSERT (((11 * 5 * PacketsResent) / PacketsSent) <= 11);
|
|
MultiplyFactor = 12 - ((11 * 5 * PacketsResent) / PacketsSent);
|
|
|
|
}
|
|
|
|
ConnectionInfo->Throughput.QuadPart =
|
|
UInt32x32To64(DeviceContext->MediumSpeed, MultiplyFactor);
|
|
|
|
} else if (!Link->ThroughputAccurate) {
|
|
|
|
//
|
|
// If throughput is not known, then guess. We
|
|
// have MediumSpeed in units of 100 bps; we
|
|
// return four times that number as the throughput,
|
|
// which corresponds to about 1/3 of the
|
|
// maximum bandwidth expressed in bytes/sec.
|
|
//
|
|
|
|
ConnectionInfo->Throughput.QuadPart =
|
|
UInt32x32To64(DeviceContext->MediumSpeed, 4);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Throughput is accurate, return it.
|
|
//
|
|
|
|
ConnectionInfo->Throughput = Link->Throughput;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Calculate reliability using the sent/resent ratio,
|
|
// if there has been enough activity to make it
|
|
// worthwhile. >10% resent is unreliable.
|
|
//
|
|
|
|
if ((Link->PacketsResent > 0) &&
|
|
(Link->PacketsSent > 20)) {
|
|
|
|
ConnectionInfo->Unreliable =
|
|
((Link->PacketsSent / Link->PacketsResent) < 10);
|
|
|
|
} else {
|
|
|
|
ConnectionInfo->Unreliable = FALSE;
|
|
|
|
}
|
|
|
|
ConnectionInfo->TransmittedTsdus = Connection->TransmittedTsdus;
|
|
ConnectionInfo->ReceivedTsdus = Connection->ReceivedTsdus;
|
|
ConnectionInfo->TransmissionErrors = Connection->TransmissionErrors;
|
|
ConnectionInfo->ReceiveErrors = Connection->ReceiveErrors;
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
(PVOID)ConnectionInfo,
|
|
0L,
|
|
sizeof(TDI_CONNECTION_INFO),
|
|
Irp->MdlAddress,
|
|
0,
|
|
&BytesCopied);
|
|
|
|
Irp->IoStatus.Information = BytesCopied;
|
|
|
|
ExFreePool (ConnectionInfo);
|
|
}
|
|
|
|
NbfDereferenceConnection ("query connection info", Connection, CREF_BY_ID);
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_ADDRESS_INFO:
|
|
|
|
if (irpSp->FileObject->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
|
|
|
|
AddressFile = irpSp->FileObject->FsContext;
|
|
|
|
status = NbfVerifyAddressObject(AddressFile);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
#if DBG
|
|
NbfPrint2 ("TdiQueryInfo: Invalid AddressFile %lx Irp %lx\n", AddressFile, Irp);
|
|
#endif
|
|
return status;
|
|
}
|
|
|
|
UsedConnection = FALSE;
|
|
|
|
} else if (irpSp->FileObject->FsContext2 == (PVOID)TDI_CONNECTION_FILE) {
|
|
|
|
Connection = irpSp->FileObject->FsContext;
|
|
|
|
status = NbfVerifyConnectionObject (Connection);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
#if DBG
|
|
NbfPrint2 ("TdiQueryInfo: Invalid Connection %lx Irp %lx\n", Connection, Irp);
|
|
#endif
|
|
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,
|
|
&BytesCopied);
|
|
|
|
Irp->IoStatus.Information = BytesCopied;
|
|
|
|
if (UsedConnection) {
|
|
|
|
NbfDereferenceConnection ("query address info", Connection, CREF_BY_ID);
|
|
|
|
} else {
|
|
|
|
NbfDereferenceAddress ("query address info", Address, AREF_VERIFY);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_BROADCAST_ADDRESS:
|
|
|
|
//
|
|
// for this provider, the broadcast address is a zero byte name,
|
|
// contained in a Transport address structure.
|
|
//
|
|
|
|
broadcastAddress = ExAllocatePoolWithTag (
|
|
NonPagedPool,
|
|
sizeof (TA_NETBIOS_ADDRESS),
|
|
NBF_MEM_TAG_TDI_QUERY_BUFFER);
|
|
if (broadcastAddress == NULL) {
|
|
PANIC ("NbfQueryInfo: Cannot allocate broadcast address!\n");
|
|
NbfWriteResourceErrorLog(
|
|
DeviceContext,
|
|
EVENT_TRANSPORT_RESOURCE_POOL,
|
|
2,
|
|
sizeof(TA_NETBIOS_ADDRESS),
|
|
0);
|
|
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);
|
|
|
|
BytesCopied = (ULONG)Irp->IoStatus.Information;
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
(PVOID)broadcastAddress,
|
|
0L,
|
|
BytesCopied,
|
|
Irp->MdlAddress,
|
|
0,
|
|
&BytesCopied);
|
|
|
|
Irp->IoStatus.Information = BytesCopied;
|
|
|
|
ExFreePool (broadcastAddress);
|
|
}
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_PROVIDER_INFO:
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
&(DeviceContext->Information),
|
|
0,
|
|
sizeof (TDI_PROVIDER_INFO),
|
|
Irp->MdlAddress,
|
|
0,
|
|
&BytesCopied);
|
|
|
|
Irp->IoStatus.Information = BytesCopied;
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_PROVIDER_STATISTICS:
|
|
|
|
//
|
|
// This information is probablt available somewhere else.
|
|
//
|
|
|
|
NbfGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
|
|
|
|
if (TargetBufferLength < sizeof(TDI_PROVIDER_STATISTICS) + ((NBF_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS))) {
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
|
|
} else {
|
|
|
|
ProviderStatistics = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(TDI_PROVIDER_STATISTICS) +
|
|
((NBF_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)),
|
|
NBF_MEM_TAG_TDI_PROVIDER_STATS);
|
|
|
|
if (ProviderStatistics == NULL) {
|
|
|
|
PANIC ("NbfQueryInfo: Cannot allocate provider statistics!\n");
|
|
NbfWriteResourceErrorLog(
|
|
DeviceContext,
|
|
EVENT_TRANSPORT_RESOURCE_POOL,
|
|
7,
|
|
sizeof(TDI_PROVIDER_STATISTICS),
|
|
0);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
NbfStoreProviderStatistics (DeviceContext, ProviderStatistics);
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
(PVOID)ProviderStatistics,
|
|
0L,
|
|
sizeof(TDI_PROVIDER_STATISTICS) +
|
|
((NBF_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)),
|
|
Irp->MdlAddress,
|
|
0,
|
|
&BytesCopied);
|
|
|
|
Irp->IoStatus.Information = BytesCopied;
|
|
|
|
ExFreePool (ProviderStatistics);
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_SESSION_STATUS:
|
|
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case TDI_QUERY_ADAPTER_STATUS:
|
|
|
|
NbfGetMdlChainLength (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.
|
|
//
|
|
|
|
RemoteAdapterStatus = FALSE;
|
|
|
|
if (query->RequestConnectionInformation != NULL) {
|
|
|
|
if (!NbfValidateTdiAddress(
|
|
query->RequestConnectionInformation->RemoteAddress,
|
|
query->RequestConnectionInformation->RemoteAddressLength)) {
|
|
return STATUS_BAD_NETWORK_PATH;
|
|
}
|
|
|
|
RemoteAddress = NbfParseTdiAddress(query->RequestConnectionInformation->RemoteAddress, FALSE);
|
|
|
|
if (!RemoteAddress) {
|
|
return STATUS_BAD_NETWORK_PATH;
|
|
}
|
|
if (!RtlEqualMemory(
|
|
RemoteAddress->NetbiosName,
|
|
DeviceContext->ReservedNetBIOSAddress,
|
|
NETBIOS_NAME_LENGTH)) {
|
|
|
|
RemoteAdapterStatus = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
if (RemoteAdapterStatus) {
|
|
|
|
//
|
|
// We need a request object to keep track of this TDI request.
|
|
// Attach this request to the device context.
|
|
//
|
|
|
|
status = NbfCreateRequest (
|
|
Irp, // IRP for this request.
|
|
DeviceContext, // context.
|
|
REQUEST_FLAGS_DC, // partial flags.
|
|
Irp->MdlAddress, // the data to be received.
|
|
TargetBufferLength, // length of the data.
|
|
timeout, // do this ourselves here.
|
|
&tpRequest);
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
|
|
NbfReferenceDeviceContext ("Remote status", DeviceContext, DCREF_REQUEST);
|
|
tpRequest->Owner = DeviceContextType;
|
|
|
|
//
|
|
// Allocate a temp buffer to hold our results.
|
|
//
|
|
|
|
tpRequest->ResponseBuffer = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
TargetBufferLength,
|
|
NBF_MEM_TAG_TDI_QUERY_BUFFER);
|
|
|
|
if (tpRequest->ResponseBuffer == NULL) {
|
|
|
|
NbfWriteResourceErrorLog(
|
|
DeviceContext,
|
|
EVENT_TRANSPORT_RESOURCE_POOL,
|
|
12,
|
|
TargetBufferLength,
|
|
0);
|
|
NbfCompleteRequest (tpRequest, STATUS_INSUFFICIENT_RESOURCES, 0);
|
|
|
|
} else {
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
|
|
|
|
if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
|
|
NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);
|
|
|
|
} else {
|
|
|
|
PUCHAR SingleSR;
|
|
UINT SingleSRLength;
|
|
|
|
InsertTailList (
|
|
&DeviceContext->StatusQueryQueue,
|
|
&tpRequest->Linkage);
|
|
|
|
tpRequest->FrameContext = DeviceContext->UniqueIdentifier | 0x8000;
|
|
++DeviceContext->UniqueIdentifier;
|
|
if (DeviceContext->UniqueIdentifier == 0x8000) {
|
|
DeviceContext->UniqueIdentifier = 1;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
//
|
|
// The request is queued. Now send out the first packet and
|
|
// start the timer.
|
|
//
|
|
|
|
tpRequest->Retries = DeviceContext->GeneralRetries;
|
|
tpRequest->BytesWritten = 0;
|
|
|
|
//
|
|
// STATUS_QUERY frames go out as
|
|
// single-route source routing.
|
|
//
|
|
|
|
MacReturnSingleRouteSR(
|
|
&DeviceContext->MacInfo,
|
|
&SingleSR,
|
|
&SingleSRLength);
|
|
|
|
NbfSendStatusQuery(
|
|
DeviceContext,
|
|
tpRequest,
|
|
&DeviceContext->NetBIOSAddress,
|
|
SingleSR,
|
|
SingleSRLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// As long as the request is created, pend here.
|
|
// The IRP will complete when the request completes.
|
|
//
|
|
|
|
status = STATUS_PENDING;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Local.
|
|
//
|
|
|
|
adapterStatus = ExAllocatePoolWithTag (
|
|
NonPagedPool,
|
|
TargetBufferLength,
|
|
NBF_MEM_TAG_TDI_QUERY_BUFFER);
|
|
|
|
if (adapterStatus == NULL) {
|
|
PANIC("NbfQueryInfo: PANIC! Could not allocate adapter status buffer\n");
|
|
NbfWriteResourceErrorLog(
|
|
DeviceContext,
|
|
EVENT_TRANSPORT_RESOURCE_POOL,
|
|
3,
|
|
TargetBufferLength,
|
|
0);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
NbfStoreAdapterStatus (
|
|
DeviceContext,
|
|
NULL,
|
|
0,
|
|
adapterStatus);
|
|
|
|
NbfStoreNameBuffers (
|
|
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,
|
|
&BytesCopied);
|
|
|
|
Irp->IoStatus.Information = BytesCopied;
|
|
|
|
if (Truncated) {
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
ExFreePool (adapterStatus);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_FIND_NAME:
|
|
|
|
NbfGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
|
|
|
|
//
|
|
// Check that there is a valid Netbios remote address.
|
|
//
|
|
|
|
if (!NbfValidateTdiAddress(
|
|
query->RequestConnectionInformation->RemoteAddress,
|
|
query->RequestConnectionInformation->RemoteAddressLength)) {
|
|
return STATUS_BAD_NETWORK_PATH;
|
|
}
|
|
|
|
RemoteAddress = NbfParseTdiAddress(query->RequestConnectionInformation->RemoteAddress, FALSE);
|
|
|
|
if (!RemoteAddress) {
|
|
return STATUS_BAD_NETWORK_PATH;
|
|
}
|
|
|
|
//
|
|
// We need a request object to keep track of this TDI request.
|
|
// Attach this request to the device context.
|
|
//
|
|
|
|
status = NbfCreateRequest (
|
|
Irp, // IRP for this request.
|
|
DeviceContext, // context.
|
|
REQUEST_FLAGS_DC, // partial flags.
|
|
Irp->MdlAddress, // the data to be received.
|
|
TargetBufferLength, // length of the data.
|
|
timeout, // do this ourselves here.
|
|
&tpRequest);
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
|
|
NbfReferenceDeviceContext ("Find name", DeviceContext, DCREF_REQUEST);
|
|
tpRequest->Owner = DeviceContextType;
|
|
|
|
//
|
|
// Allocate a temp buffer to hold our results.
|
|
//
|
|
|
|
tpRequest->ResponseBuffer = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
TargetBufferLength,
|
|
NBF_MEM_TAG_TDI_QUERY_BUFFER);
|
|
|
|
if (tpRequest->ResponseBuffer == NULL) {
|
|
|
|
NbfWriteResourceErrorLog(
|
|
DeviceContext,
|
|
EVENT_TRANSPORT_RESOURCE_POOL,
|
|
4,
|
|
TargetBufferLength,
|
|
0);
|
|
NbfCompleteRequest (tpRequest, STATUS_INSUFFICIENT_RESOURCES, 0);
|
|
|
|
} else {
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
|
|
|
|
if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
|
|
NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);
|
|
|
|
} else {
|
|
|
|
InsertTailList (
|
|
&DeviceContext->FindNameQueue,
|
|
&tpRequest->Linkage);
|
|
|
|
tpRequest->FrameContext = DeviceContext->UniqueIdentifier | 0x8000;
|
|
++DeviceContext->UniqueIdentifier;
|
|
if (DeviceContext->UniqueIdentifier == 0x8000) {
|
|
DeviceContext->UniqueIdentifier = 1;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
//
|
|
// The request is queued. Now send out the first packet and
|
|
// start the timer.
|
|
//
|
|
// We fill in the FIND_NAME_HEADER in the buffer, but
|
|
// set BytesWritten to 0; we don't include the header
|
|
// in BytesWritten until we get a response, so that
|
|
// a BytesWritten of 0 means "no response".
|
|
//
|
|
|
|
tpRequest->Retries = DeviceContext->GeneralRetries;
|
|
tpRequest->BytesWritten = 0;
|
|
FindNameHeader = (PFIND_NAME_HEADER)tpRequest->ResponseBuffer;
|
|
FindNameHeader->node_count = 0;
|
|
FindNameHeader->unique_group = NETBIOS_NAME_TYPE_UNIQUE;
|
|
|
|
NbfSendQueryFindName (DeviceContext, tpRequest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// As long as the request is created, pend here.
|
|
// The IRP will complete when the request completes.
|
|
//
|
|
|
|
status = STATUS_PENDING;
|
|
}
|
|
|
|
break;
|
|
|
|
case TDI_QUERY_DATA_LINK_ADDRESS:
|
|
case TDI_QUERY_NETWORK_ADDRESS:
|
|
|
|
TaAddress = (PTRANSPORT_ADDRESS)&AddressInfo.TaAddressBuffer;
|
|
TaAddress->TAAddressCount = 1;
|
|
TaAddress->Address[0].AddressLength = 6;
|
|
if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
|
|
TaAddress->Address[0].AddressType =
|
|
DeviceContext->MacInfo.MediumAsync ?
|
|
NdisMediumWan : DeviceContext->MacInfo.MediumType;
|
|
} else {
|
|
TaAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_UNSPEC;
|
|
}
|
|
RtlCopyMemory (TaAddress->Address[0].Address, DeviceContext->LocalAddress.Address, 6);
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
&AddressInfo.TaAddressBuffer,
|
|
0,
|
|
sizeof(TRANSPORT_ADDRESS)+5,
|
|
Irp->MdlAddress,
|
|
0,
|
|
&BytesCopied);
|
|
|
|
Irp->IoStatus.Information = BytesCopied;
|
|
break;
|
|
|
|
case TDI_QUERY_DATAGRAM_INFO:
|
|
|
|
DatagramInfo.MaximumDatagramBytes = 0;
|
|
DatagramInfo.MaximumDatagramCount = 0;
|
|
|
|
status = TdiCopyBufferToMdl (
|
|
&DatagramInfo,
|
|
0,
|
|
sizeof(DatagramInfo),
|
|
Irp->MdlAddress,
|
|
0,
|
|
&BytesCopied);
|
|
|
|
Irp->IoStatus.Information = BytesCopied;
|
|
break;
|
|
|
|
default:
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
|
|
} /* NbfTdiQueryInformation */
|
|
|
|
//
|
|
// 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
|
|
NbfStoreProviderStatistics(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Copy all the statistics up to NumberOfResources
|
|
// in one move.
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
ProviderStatistics,
|
|
&DeviceContext->Statistics,
|
|
FIELD_OFFSET (TDI_PROVIDER_STATISTICS, NumberOfResources));
|
|
|
|
//
|
|
// Calculate AverageSendWindow.
|
|
//
|
|
|
|
if (DeviceContext->SendWindowSamples > 0) {
|
|
ProviderStatistics->AverageSendWindow =
|
|
DeviceContext->SendWindowTotal / DeviceContext->SendWindowSamples;
|
|
} else {
|
|
ProviderStatistics->AverageSendWindow = 1;
|
|
}
|
|
|
|
//
|
|
// Copy the resource statistics.
|
|
//
|
|
|
|
ProviderStatistics->NumberOfResources = NBF_TDI_RESOURCES;
|
|
|
|
STORE_RESOURCE_STATS_1 (0, LINK_RESOURCE_ID, Link);
|
|
STORE_RESOURCE_STATS_1 (1, ADDRESS_RESOURCE_ID, Address);
|
|
STORE_RESOURCE_STATS_1 (2, ADDRESS_FILE_RESOURCE_ID, AddressFile);
|
|
STORE_RESOURCE_STATS_1 (3, CONNECTION_RESOURCE_ID, Connection);
|
|
STORE_RESOURCE_STATS_1 (4, REQUEST_RESOURCE_ID, Request);
|
|
|
|
STORE_RESOURCE_STATS_2 (5, UI_FRAME_RESOURCE_ID, UIFrame);
|
|
STORE_RESOURCE_STATS_2 (6, PACKET_RESOURCE_ID, Packet);
|
|
STORE_RESOURCE_STATS_2 (7, RECEIVE_PACKET_RESOURCE_ID, ReceivePacket);
|
|
STORE_RESOURCE_STATS_2 (8, RECEIVE_BUFFER_RESOURCE_ID, ReceiveBuffer);
|
|
|
|
} /* NbfStoreProviderStatistics */
|
|
|
|
|
|
VOID
|
|
NbfStoreAdapterStatus(
|
|
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; NbfStoreNameBuffers 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 = (WORD)DeviceContext->FrmrReceived;
|
|
AdapterStatus->frmr_xmit = (WORD)DeviceContext->FrmrTransmitted;
|
|
|
|
AdapterStatus->recv_buff_unavail = (WORD)(DeviceContext->ReceivePacketExhausted + DeviceContext->ReceiveBufferExhausted);
|
|
AdapterStatus->xmit_buf_unavail = (WORD)DeviceContext->PacketExhausted;
|
|
|
|
AdapterStatus->xmit_success = (WORD)(DeviceContext->Statistics.DataFramesSent - DeviceContext->Statistics.DataFramesResent);
|
|
AdapterStatus->recv_success = (WORD)DeviceContext->Statistics.DataFramesReceived;
|
|
AdapterStatus->iframe_recv_err = (WORD)DeviceContext->Statistics.DataFramesRejected;
|
|
AdapterStatus->iframe_xmit_err = (WORD)DeviceContext->Statistics.DataFramesResent;
|
|
|
|
AdapterStatus->t1_timeouts = (WORD)DeviceContext->Statistics.ResponseTimerExpirations;
|
|
AdapterStatus->ti_timeouts = (WORD)DeviceContext->TiExpirations;
|
|
AdapterStatus->xmit_aborts = (WORD)0;
|
|
|
|
|
|
AdapterStatus->free_ncbs = (WORD)0xffff;
|
|
AdapterStatus->max_cfg_ncbs = (WORD)0xffff;
|
|
AdapterStatus->max_ncbs = (WORD)0xffff;
|
|
AdapterStatus->pending_sess = (WORD)DeviceContext->Statistics.OpenConnections;
|
|
AdapterStatus->max_cfg_sess = (WORD)0xffff;
|
|
AdapterStatus->max_sess = (WORD)0xffff;
|
|
|
|
|
|
MacReturnMaxDataSize(
|
|
&DeviceContext->MacInfo,
|
|
NULL,
|
|
0,
|
|
DeviceContext->MaxSendPacketSize,
|
|
TRUE,
|
|
&MaxUserData);
|
|
AdapterStatus->max_dgram_size = (WORD)(MaxUserData - (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS)));
|
|
|
|
MacReturnMaxDataSize(
|
|
&DeviceContext->MacInfo,
|
|
SourceRouting,
|
|
SourceRoutingLength,
|
|
DeviceContext->MaxSendPacketSize,
|
|
FALSE,
|
|
&MaxUserData);
|
|
AdapterStatus->max_sess_pkt_size = (WORD)(MaxUserData - (sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION)));
|
|
|
|
return;
|
|
|
|
} /* NbfStoreAdapterStatus */
|
|
|
|
|
|
VOID
|
|
NbfStoreNameBuffers(
|
|
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;
|
|
}
|
|
|
|
// name_flags should be done more accurately.
|
|
|
|
BytesWritten += sizeof(NAME_BUFFER);
|
|
++NameBuffer;
|
|
|
|
}
|
|
|
|
*NamesWritten = (ULONG)(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;
|
|
|
|
} /* NbfStoreNameBuffers */
|
|
|
|
|
|
NTSTATUS
|
|
NbfProcessStatusQuery(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PTP_ADDRESS Address OPTIONAL,
|
|
IN PNBF_HDR_CONNECTIONLESS UiFrame,
|
|
IN PHARDWARE_ADDRESS SourceAddress,
|
|
IN PUCHAR SourceRouting,
|
|
IN UINT SourceRoutingLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes a STATUS.QUERY packet.
|
|
|
|
Arguments:
|
|
|
|
DeviceContext - a pointer to the device context the frame was received on.
|
|
|
|
Address - The address we are responding from, or NULL if the STATUS.QUERY
|
|
was sent to the reserved address.
|
|
|
|
UiFrame - The packet in question, starting at the Netbios header.
|
|
|
|
SourceAddress - The source hardware address of the packet.
|
|
|
|
SourceRouting - Source routing data in the query.
|
|
|
|
SourceRoutingLength - The length of SourceRouting.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
NDIS_STATUS NdisStatus;
|
|
PTP_UI_FRAME RawFrame;
|
|
PVOID ResponseBuffer;
|
|
UINT ResponseBufferLength;
|
|
ULONG NamesWritten, TotalNameCount;
|
|
ULONG BytesWritten;
|
|
UCHAR RequestType;
|
|
BOOLEAN Truncated, UsersBufferTooShort;
|
|
USHORT UsersBufferLength;
|
|
UINT HeaderLength;
|
|
UCHAR TempSR[MAX_SOURCE_ROUTING];
|
|
PUCHAR ResponseSR;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
|
|
//
|
|
// Allocate a buffer to hold the status.
|
|
//
|
|
|
|
MacReturnMaxDataSize(
|
|
&DeviceContext->MacInfo,
|
|
SourceRouting,
|
|
SourceRoutingLength,
|
|
DeviceContext->CurSendPacketSize,
|
|
FALSE,
|
|
&ResponseBufferLength);
|
|
|
|
ResponseBufferLength -= (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS));
|
|
|
|
UsersBufferLength = (UiFrame->Data2High * 256) + UiFrame->Data2Low;
|
|
|
|
//
|
|
// See how big to make our buffer; if the amount remaining in the user's
|
|
// buffer is less than our max size, chop it down.
|
|
//
|
|
|
|
if (UiFrame->Data1 <= 1) {
|
|
|
|
//
|
|
// This is the initial request.
|
|
//
|
|
|
|
if (ResponseBufferLength > (UINT)UsersBufferLength) {
|
|
ResponseBufferLength = UsersBufferLength;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Subsequent request; compensate for already-sent data.
|
|
//
|
|
|
|
UsersBufferLength -= (sizeof(ADAPTER_STATUS) + (UiFrame->Data1 * sizeof(NAME_BUFFER)));
|
|
|
|
if (ResponseBufferLength > (UINT)UsersBufferLength) {
|
|
ResponseBufferLength = UsersBufferLength;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If the remote station is asking for no data, ignore this request.
|
|
// This prevents us from trying to allocate 0 bytes of pool.
|
|
//
|
|
|
|
if ( (LONG)ResponseBufferLength <= 0 ) {
|
|
return STATUS_ABANDONED;
|
|
}
|
|
|
|
ResponseBuffer = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
ResponseBufferLength,
|
|
NBF_MEM_TAG_TDI_QUERY_BUFFER);
|
|
|
|
if (ResponseBuffer == NULL) {
|
|
NbfWriteResourceErrorLog(
|
|
DeviceContext,
|
|
EVENT_TRANSPORT_RESOURCE_POOL,
|
|
5,
|
|
ResponseBufferLength,
|
|
0);
|
|
return STATUS_ABANDONED;
|
|
}
|
|
|
|
|
|
//
|
|
// Fill in the response buffer.
|
|
//
|
|
|
|
if (UiFrame->Data1 <= 1) {
|
|
|
|
//
|
|
// First request.
|
|
//
|
|
|
|
NbfStoreAdapterStatus (
|
|
DeviceContext,
|
|
SourceRouting,
|
|
SourceRoutingLength,
|
|
ResponseBuffer);
|
|
|
|
NbfStoreNameBuffers (
|
|
DeviceContext,
|
|
(PUCHAR)ResponseBuffer + sizeof(ADAPTER_STATUS),
|
|
ResponseBufferLength - sizeof(ADAPTER_STATUS),
|
|
0,
|
|
&NamesWritten,
|
|
&TotalNameCount,
|
|
&Truncated);
|
|
|
|
BytesWritten = sizeof(ADAPTER_STATUS) + (NamesWritten * sizeof(NAME_BUFFER));
|
|
|
|
//
|
|
// If the data was truncated, but we are returning the maximum
|
|
// that the user requested, report that as "user's buffer
|
|
// too short" instead of "truncated".
|
|
//
|
|
|
|
if (Truncated && (ResponseBufferLength >= (UINT)UsersBufferLength)) {
|
|
Truncated = FALSE;
|
|
UsersBufferTooShort = TRUE;
|
|
} else {
|
|
UsersBufferTooShort = FALSE;
|
|
}
|
|
|
|
((PADAPTER_STATUS)ResponseBuffer)->name_count = (WORD)TotalNameCount;
|
|
|
|
} else {
|
|
|
|
NbfStoreNameBuffers (
|
|
DeviceContext,
|
|
ResponseBuffer,
|
|
ResponseBufferLength,
|
|
UiFrame->Data1,
|
|
&NamesWritten,
|
|
NULL,
|
|
&Truncated);
|
|
|
|
BytesWritten = NamesWritten * sizeof(NAME_BUFFER);
|
|
|
|
if (Truncated && (ResponseBufferLength >= (UINT)UsersBufferLength)) {
|
|
Truncated = FALSE;
|
|
UsersBufferTooShort = TRUE;
|
|
} else {
|
|
UsersBufferTooShort = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate a UI frame from the pool.
|
|
//
|
|
|
|
Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
|
|
if (!NT_SUCCESS (Status)) { // couldn't make frame.
|
|
ExFreePool (ResponseBuffer);
|
|
return STATUS_ABANDONED;
|
|
}
|
|
|
|
IF_NBFDBG (NBF_DEBUG_DEVCTX) {
|
|
NbfPrint2 ("NbfProcessStatusQuery: Sending Frame: %lx, NdisPacket: %lx\n",
|
|
RawFrame, RawFrame->NdisPacket);
|
|
}
|
|
|
|
|
|
//
|
|
// Build the MAC header. STATUS_RESPONSE frames go out as
|
|
// non-broadcast source routing.
|
|
//
|
|
|
|
if (SourceRouting != NULL) {
|
|
|
|
RtlCopyMemory(
|
|
TempSR,
|
|
SourceRouting,
|
|
SourceRoutingLength);
|
|
|
|
MacCreateNonBroadcastReplySR(
|
|
&DeviceContext->MacInfo,
|
|
TempSR,
|
|
SourceRoutingLength,
|
|
&ResponseSR);
|
|
|
|
} else {
|
|
|
|
ResponseSR = NULL;
|
|
|
|
}
|
|
|
|
MacConstructHeader (
|
|
&DeviceContext->MacInfo,
|
|
RawFrame->Header,
|
|
SourceAddress->Address,
|
|
DeviceContext->LocalAddress.Address,
|
|
sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS) + BytesWritten,
|
|
ResponseSR,
|
|
SourceRoutingLength,
|
|
&HeaderLength);
|
|
|
|
|
|
//
|
|
// Build the DLC UI frame header.
|
|
//
|
|
|
|
NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
|
|
HeaderLength += sizeof(DLC_FRAME);
|
|
|
|
|
|
//
|
|
// Build the Netbios header.
|
|
//
|
|
|
|
switch (UiFrame->Data1) {
|
|
case 0: // pre 2.1 request
|
|
RequestType = (UCHAR)0;
|
|
break;
|
|
case 1: // 2.1, first request
|
|
RequestType = (UCHAR)NamesWritten;
|
|
break;
|
|
default: // 2.1, subsequent request
|
|
RequestType = (UCHAR)(UiFrame->Data1 + NamesWritten);
|
|
break;
|
|
}
|
|
|
|
ConstructStatusResponse (
|
|
(PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
|
|
RequestType, // request type.
|
|
Truncated, // more data.
|
|
UsersBufferTooShort, // user's buffer too small
|
|
(USHORT)BytesWritten, // bytes in response
|
|
RESPONSE_CORR(UiFrame), // correlator
|
|
UiFrame->SourceName, // receiver permanent name
|
|
(ARGUMENT_PRESENT(Address)) ?
|
|
Address->NetworkName->NetbiosName :
|
|
DeviceContext->ReservedNetBIOSAddress); // source name
|
|
|
|
HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
|
|
|
|
|
|
//
|
|
// Munge the packet length (now, before we append the second
|
|
// buffer).
|
|
//
|
|
|
|
NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
|
|
|
|
|
|
//
|
|
// Now, if we have any name data, attach our buffer onto the frame.
|
|
// Note that it's possible at the end of the user's buffer for us
|
|
// to not have room for any names, and thus we'll have no data to
|
|
// send.
|
|
//
|
|
|
|
if ( BytesWritten != 0 ) {
|
|
|
|
RawFrame->DataBuffer = ResponseBuffer;
|
|
|
|
NdisAllocateBuffer(
|
|
&NdisStatus,
|
|
&NdisBuffer,
|
|
DeviceContext->NdisBufferPool,
|
|
ResponseBuffer,
|
|
BytesWritten);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
PANIC ("ConstructStatusResponse: NdisAllocateBuffer failed.\n");
|
|
NbfDestroyConnectionlessFrame (DeviceContext, RawFrame);
|
|
return STATUS_ABANDONED;
|
|
}
|
|
|
|
NdisChainBufferAtBack (RawFrame->NdisPacket, NdisBuffer);
|
|
|
|
} else {
|
|
|
|
RawFrame->DataBuffer = NULL;
|
|
|
|
}
|
|
|
|
|
|
NbfSendUIFrame (
|
|
DeviceContext,
|
|
RawFrame,
|
|
FALSE); // no loopback (MC frame)
|
|
|
|
return STATUS_ABANDONED;
|
|
|
|
} /* NbfProcessStatusQuery */
|
|
|
|
|
|
VOID
|
|
NbfSendQueryFindName(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PTP_REQUEST Request
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will send a FIND.NAME packet for the specified
|
|
find name request, and start the request timer.
|
|
|
|
Arguments:
|
|
|
|
DeviceContext - a pointer to the device context to send the find name on.
|
|
|
|
Request - The find name request.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
TDI_ADDRESS_NETBIOS * remoteAddress;
|
|
PIO_STACK_LOCATION irpSp;
|
|
NTSTATUS Status;
|
|
PTP_UI_FRAME RawFrame;
|
|
PUCHAR SingleSR;
|
|
UINT SingleSRLength;
|
|
UINT HeaderLength;
|
|
LARGE_INTEGER Timeout;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
|
|
|
|
remoteAddress = NbfParseTdiAddress(
|
|
((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)(&irpSp->Parameters))->
|
|
RequestConnectionInformation->RemoteAddress, FALSE);
|
|
|
|
//
|
|
// Start the timer for this request.
|
|
//
|
|
|
|
Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
|
|
KeInitializeTimer (&Request->Timer); // set to not-signaled state.
|
|
NbfReferenceRequest ("Find Name: timer", Request, RREF_TIMER); // one for the timer
|
|
Timeout.LowPart = (ULONG)(-(LONG)DeviceContext->GeneralTimeout);
|
|
Timeout.HighPart = -1;
|
|
KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
|
|
|
|
//
|
|
// Allocate a UI frame from the pool.
|
|
//
|
|
|
|
Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
|
|
if (!NT_SUCCESS (Status)) { // couldn't make frame.
|
|
return;
|
|
}
|
|
|
|
IF_NBFDBG (NBF_DEBUG_DEVCTX) {
|
|
NbfPrint2 ("NbfSendFindNames: Sending Frame: %lx, NdisPacket: %lx\n",
|
|
RawFrame, RawFrame->NdisPacket);
|
|
}
|
|
|
|
|
|
//
|
|
// Build the MAC header. NAME_QUERY frames go out as
|
|
// single-route source routing.
|
|
//
|
|
|
|
MacReturnSingleRouteSR(
|
|
&DeviceContext->MacInfo,
|
|
&SingleSR,
|
|
&SingleSRLength);
|
|
|
|
MacConstructHeader (
|
|
&DeviceContext->MacInfo,
|
|
RawFrame->Header,
|
|
DeviceContext->NetBIOSAddress.Address,
|
|
DeviceContext->LocalAddress.Address,
|
|
sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
|
|
SingleSR,
|
|
SingleSRLength,
|
|
&HeaderLength);
|
|
|
|
|
|
//
|
|
// Build the DLC UI frame header.
|
|
//
|
|
|
|
NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
|
|
HeaderLength += sizeof(DLC_FRAME);
|
|
|
|
|
|
//
|
|
// Build the Netbios header.
|
|
//
|
|
|
|
ConstructNameQuery (
|
|
(PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
|
|
NETBIOS_NAME_TYPE_UNIQUE, // call from a unique name.
|
|
NAME_QUERY_LSN_FIND_NAME, // LSN
|
|
Request->FrameContext, // corr. in 1st NAME_RECOGNIZED.
|
|
DeviceContext->ReservedNetBIOSAddress,
|
|
(PNAME)remoteAddress->NetbiosName);
|
|
|
|
HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
|
|
|
|
|
|
//
|
|
// Munge the packet length.
|
|
//
|
|
|
|
NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
|
|
|
|
NbfSendUIFrame (
|
|
DeviceContext,
|
|
RawFrame,
|
|
FALSE); // no loopback (MC frame)
|
|
|
|
} /* NbfSendQueryFindName */
|
|
|
|
|
|
NTSTATUS
|
|
NbfProcessQueryNameRecognized(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PUCHAR Packet,
|
|
PNBF_HDR_CONNECTIONLESS UiFrame
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes a NAME.RECOGNIZED request with a
|
|
correlator of 0, indicating it was a response to a previous
|
|
FIND.NAME packet.
|
|
|
|
Arguments:
|
|
|
|
DeviceContext - a pointer to the device context the frame was received on.
|
|
|
|
Packet - The packet in question, starting at the MAC header.
|
|
|
|
UiFrame - The packet, starting at the Netbios header.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KIRQL oldirql;
|
|
PTP_REQUEST Request;
|
|
PFIND_NAME_BUFFER FindNameBuffer;
|
|
PFIND_NAME_HEADER FindNameHeader;
|
|
PUCHAR DestinationAddress;
|
|
HARDWARE_ADDRESS SourceAddressBuffer;
|
|
PHARDWARE_ADDRESS SourceAddress;
|
|
PUCHAR SourceRouting;
|
|
UINT SourceRoutingLength;
|
|
PUCHAR TargetBuffer;
|
|
USHORT FrameContext;
|
|
PLIST_ENTRY p;
|
|
|
|
|
|
MacReturnDestinationAddress(
|
|
&DeviceContext->MacInfo,
|
|
Packet,
|
|
&DestinationAddress);
|
|
|
|
MacReturnSourceAddress(
|
|
&DeviceContext->MacInfo,
|
|
Packet,
|
|
&SourceAddressBuffer,
|
|
&SourceAddress,
|
|
NULL);
|
|
|
|
MacReturnSourceRouting(
|
|
&DeviceContext->MacInfo,
|
|
Packet,
|
|
&SourceRouting,
|
|
&SourceRoutingLength);
|
|
|
|
//
|
|
// Find the request that this is for, using the frame context.
|
|
//
|
|
|
|
FrameContext = TRANSMIT_CORR(UiFrame);
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
|
|
|
|
for (p=DeviceContext->FindNameQueue.Flink;
|
|
p != &DeviceContext->FindNameQueue;
|
|
p=p->Flink) {
|
|
|
|
Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
|
|
|
|
if (Request->FrameContext == FrameContext) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (p == &DeviceContext->FindNameQueue) {
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NbfReferenceRequest ("Name Recognized", Request, RREF_FIND_NAME);
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
//
|
|
// Make sure that this physical address has not
|
|
// responded yet.
|
|
//
|
|
|
|
ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
|
|
|
|
//
|
|
// Make sure this request is not stopping.
|
|
//
|
|
|
|
if ((Request->Flags & REQUEST_FLAGS_STOPPING) != 0) {
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
NbfDereferenceRequest ("Stopping", Request, RREF_STATUS);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// If this is the first response, update BytesWritten to include
|
|
// the header that is already written in ResponseBuffer.
|
|
//
|
|
|
|
if (Request->BytesWritten == 0) {
|
|
Request->BytesWritten = sizeof(FIND_NAME_HEADER);
|
|
}
|
|
|
|
TargetBuffer = Request->ResponseBuffer;
|
|
FindNameBuffer = (PFIND_NAME_BUFFER)(TargetBuffer + sizeof(FIND_NAME_HEADER));
|
|
|
|
for ( ; FindNameBuffer < (PFIND_NAME_BUFFER)(TargetBuffer + Request->BytesWritten); FindNameBuffer++) {
|
|
|
|
if (RtlEqualMemory (FindNameBuffer->source_addr, SourceAddress->Address, 6)) {
|
|
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
NbfDereferenceRequest ("Duplicate NR", Request, RREF_FIND_NAME);
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// This is a new address, update if there is room.
|
|
//
|
|
|
|
if ((Request->BytesWritten + sizeof(FIND_NAME_BUFFER)) >
|
|
Request->Buffer2Length) {
|
|
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
|
|
RemoveEntryList (&Request->Linkage);
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
NbfCompleteRequest (Request, STATUS_SUCCESS, Request->BytesWritten);
|
|
NbfDereferenceRequest ("No Buffer", Request, RREF_FIND_NAME);
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
FindNameHeader = (PFIND_NAME_HEADER)TargetBuffer;
|
|
FindNameHeader->unique_group = UiFrame->Data2High;
|
|
|
|
Request->BytesWritten += sizeof(FIND_NAME_BUFFER);
|
|
++FindNameHeader->node_count;
|
|
|
|
RtlCopyMemory(FindNameBuffer->source_addr, SourceAddress->Address, 6);
|
|
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
|
|
RtlCopyMemory(FindNameBuffer->destination_addr, DestinationAddress, 6);
|
|
FindNameBuffer->length = 14;
|
|
|
|
if (DeviceContext->MacInfo.MediumType == NdisMedium802_5) {
|
|
|
|
//
|
|
// token-ring, copy the correct fields.
|
|
//
|
|
|
|
FindNameBuffer->access_control = Packet[0];
|
|
FindNameBuffer->frame_control = Packet[1];
|
|
|
|
if (SourceRouting != NULL) {
|
|
RtlCopyMemory (FindNameBuffer->routing_info, SourceRouting, SourceRoutingLength);
|
|
FindNameBuffer->length += (UCHAR) SourceRoutingLength;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// non-token-ring, nothing else is significant.
|
|
//
|
|
|
|
FindNameBuffer->access_control = 0x0;
|
|
FindNameBuffer->frame_control = 0x0;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// If this is a unique name, complete the request now.
|
|
//
|
|
|
|
if (UiFrame->Data2High == NETBIOS_NAME_TYPE_UNIQUE) {
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
|
|
RemoveEntryList (&Request->Linkage);
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
NbfCompleteRequest(Request, STATUS_SUCCESS, Request->BytesWritten);
|
|
|
|
}
|
|
|
|
NbfDereferenceRequest ("NR processed", Request, RREF_FIND_NAME);
|
|
return STATUS_SUCCESS;
|
|
|
|
} /* NbfProcessQueryNameRecognized */
|
|
|
|
|
|
VOID
|
|
NbfSendStatusQuery(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN PTP_REQUEST Request,
|
|
IN PHARDWARE_ADDRESS DestinationAddress,
|
|
IN PUCHAR SourceRouting,
|
|
IN UINT SourceRoutingLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will send a STATUS.NAME packet for the specified
|
|
find name request, and start the request timer.
|
|
|
|
Arguments:
|
|
|
|
DeviceContext - a pointer to the device context to send the status query on.
|
|
|
|
Request - The find name request.
|
|
|
|
DestinationAddress - The hardware destination address of the frame.
|
|
|
|
SourceRouting - Optional source routing information in the frame.
|
|
|
|
SourceRoutingLength - The length of SourceRouting.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
TDI_ADDRESS_NETBIOS * remoteAddress;
|
|
PIO_STACK_LOCATION irpSp;
|
|
NTSTATUS Status;
|
|
PTP_UI_FRAME RawFrame;
|
|
PUCHAR SingleSR;
|
|
UINT SingleSRLength;
|
|
UINT HeaderLength;
|
|
LARGE_INTEGER Timeout;
|
|
UCHAR RequestType;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
|
|
|
|
remoteAddress = NbfParseTdiAddress(
|
|
((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)(&irpSp->Parameters))->
|
|
RequestConnectionInformation->RemoteAddress, FALSE);
|
|
|
|
//
|
|
// Start the timer for this request.
|
|
//
|
|
|
|
Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
|
|
KeInitializeTimer (&Request->Timer); // set to not-signaled state.
|
|
NbfReferenceRequest ("Find Name: timer", Request, RREF_TIMER); // one for the timer
|
|
Timeout.LowPart = (ULONG)(-(LONG)DeviceContext->GeneralTimeout);
|
|
Timeout.HighPart = -1;
|
|
KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
|
|
|
|
//
|
|
// Allocate a UI frame from the pool.
|
|
//
|
|
|
|
Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
|
|
if (!NT_SUCCESS (Status)) { // couldn't make frame.
|
|
return;
|
|
}
|
|
|
|
IF_NBFDBG (NBF_DEBUG_DEVCTX) {
|
|
NbfPrint2 ("NbfSendFindNames: Sending Frame: %lx, NdisPacket: %lx\n",
|
|
RawFrame, RawFrame->NdisPacket);
|
|
}
|
|
|
|
|
|
//
|
|
// Build the MAC header. STATUS_QUERY frames go out as
|
|
// single-route source routing.
|
|
//
|
|
|
|
MacReturnSingleRouteSR(
|
|
&DeviceContext->MacInfo,
|
|
&SingleSR,
|
|
&SingleSRLength);
|
|
|
|
MacConstructHeader (
|
|
&DeviceContext->MacInfo,
|
|
RawFrame->Header,
|
|
DeviceContext->NetBIOSAddress.Address,
|
|
DeviceContext->LocalAddress.Address,
|
|
sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
|
|
SingleSR,
|
|
SingleSRLength,
|
|
&HeaderLength);
|
|
|
|
|
|
//
|
|
// Build the DLC UI frame header.
|
|
//
|
|
|
|
NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
|
|
HeaderLength += sizeof(DLC_FRAME);
|
|
|
|
|
|
//
|
|
// Build the Netbios header.
|
|
//
|
|
|
|
//
|
|
// Determine what RequestType should be.
|
|
//
|
|
|
|
if (Request->BytesWritten == 0) {
|
|
|
|
//
|
|
// No way to know if he is 2.1 or not, so we put a 1 here
|
|
// instead of 0.
|
|
//
|
|
|
|
RequestType = 1;
|
|
|
|
} else {
|
|
|
|
RequestType = (UCHAR)((Request->BytesWritten - sizeof(ADAPTER_STATUS)) / sizeof(NAME_BUFFER));
|
|
|
|
}
|
|
|
|
ConstructStatusQuery (
|
|
(PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
|
|
RequestType, // request status type.
|
|
(USHORT)Request->Buffer2Length, // user's buffer length
|
|
Request->FrameContext, // corr. in 1st NAME_RECOGNIZED.
|
|
(PNAME)remoteAddress->NetbiosName,
|
|
DeviceContext->ReservedNetBIOSAddress);
|
|
|
|
HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
|
|
|
|
|
|
//
|
|
// Munge the packet length.
|
|
//
|
|
|
|
NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
|
|
|
|
NbfSendUIFrame (
|
|
DeviceContext,
|
|
RawFrame,
|
|
FALSE); // no loopback (MC frame)
|
|
|
|
} /* NbfSendStatusQuery */
|
|
|
|
|
|
NTSTATUS
|
|
NbfProcessStatusResponse(
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN NDIS_HANDLE ReceiveContext,
|
|
IN PNBF_HDR_CONNECTIONLESS UiFrame,
|
|
IN PHARDWARE_ADDRESS SourceAddress,
|
|
IN PUCHAR SourceRouting,
|
|
IN UINT SourceRoutingLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes a STATUS.RESPONSE packet.
|
|
|
|
Arguments:
|
|
|
|
DeviceContext - a pointer to the device context the frame was received on.
|
|
|
|
ReceiveContext - The context for calling NdisTransferData.
|
|
|
|
UiFrame - The packet in question, starting at the Netbios header.
|
|
|
|
SourceAddress - The source hardware address of the packet.
|
|
|
|
SourceRouting - Source routing data in the query.
|
|
|
|
SourceRoutingLength - The length of SourceRouting.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KIRQL oldirql;
|
|
PTP_REQUEST Request;
|
|
PUCHAR TargetBuffer;
|
|
USHORT FrameContext;
|
|
USHORT NamesReceived;
|
|
USHORT ResponseLength, ResponseBytesToCopy;
|
|
PLIST_ENTRY p;
|
|
PSINGLE_LIST_ENTRY linkage;
|
|
NDIS_STATUS ndisStatus;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
PNDIS_PACKET ndisPacket;
|
|
ULONG ndisBytesTransferred;
|
|
PRECEIVE_PACKET_TAG receiveTag;
|
|
NDIS_STATUS NdisStatus;
|
|
|
|
|
|
//
|
|
// Find the request that this is for, using the frame context.
|
|
//
|
|
|
|
FrameContext = TRANSMIT_CORR(UiFrame);
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
|
|
|
|
for (p=DeviceContext->StatusQueryQueue.Flink;
|
|
p != &DeviceContext->StatusQueryQueue;
|
|
p=p->Flink) {
|
|
|
|
Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
|
|
|
|
if (Request->FrameContext == FrameContext) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (p == &DeviceContext->StatusQueryQueue) {
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NbfReferenceRequest ("Status Response", Request, RREF_STATUS);
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
|
|
|
|
//
|
|
// Make sure this request is not stopping.
|
|
//
|
|
|
|
if ((Request->Flags & REQUEST_FLAGS_STOPPING) != 0) {
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
NbfDereferenceRequest ("Stopping", Request, RREF_STATUS);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// See if this is packet has new data.
|
|
//
|
|
|
|
if (Request->BytesWritten == 0) {
|
|
|
|
NamesReceived = 0;
|
|
|
|
} else {
|
|
|
|
NamesReceived = (USHORT)(Request->BytesWritten - sizeof(ADAPTER_STATUS)) / sizeof(NAME_BUFFER);
|
|
|
|
}
|
|
|
|
if ((UiFrame->Data1 > 0) && (UiFrame->Data1 <= NamesReceived)) {
|
|
|
|
//
|
|
// If it is a post-2.1 response, but we already got
|
|
// this data, ignore it.
|
|
//
|
|
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
NbfDereferenceRequest ("Duplicate SR", Request, RREF_STATUS);
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// This is new data, append if there is room.
|
|
//
|
|
|
|
ResponseLength = ((UiFrame->Data2High & 0x3f) * 256) + UiFrame->Data2Low;
|
|
|
|
if ((ULONG)(Request->BytesWritten + ResponseLength) >
|
|
Request->Buffer2Length) {
|
|
|
|
ResponseBytesToCopy = (USHORT)(Request->Buffer2Length - Request->BytesWritten);
|
|
|
|
} else {
|
|
|
|
ResponseBytesToCopy = ResponseLength;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate a receive packer for this operation.
|
|
//
|
|
|
|
linkage = ExInterlockedPopEntryList(
|
|
&DeviceContext->ReceivePacketPool,
|
|
&DeviceContext->Interlock);
|
|
|
|
if (linkage != NULL) {
|
|
ndisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
|
|
} else {
|
|
|
|
//
|
|
// Could not get a packet, oh well, it is connectionless.
|
|
//
|
|
|
|
DeviceContext->ReceivePacketExhausted++;
|
|
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
receiveTag = (PRECEIVE_PACKET_TAG)(ndisPacket->ProtocolReserved);
|
|
receiveTag->PacketType = TYPE_STATUS_RESPONSE;
|
|
receiveTag->Connection = (PTP_CONNECTION)Request;
|
|
|
|
TargetBuffer = (PUCHAR)Request->ResponseBuffer + Request->BytesWritten;
|
|
|
|
//
|
|
// Allocate an MDL to describe the part of the buffer we
|
|
// want transferred.
|
|
//
|
|
|
|
NdisAllocateBuffer(
|
|
&NdisStatus,
|
|
&NdisBuffer,
|
|
DeviceContext->NdisBufferPool,
|
|
TargetBuffer,
|
|
ResponseBytesToCopy);
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
ExInterlockedPushEntryList(
|
|
&DeviceContext->ReceivePacketPool,
|
|
linkage,
|
|
&DeviceContext->Interlock);
|
|
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Assume success, if not we fail the request.
|
|
//
|
|
|
|
Request->BytesWritten += ResponseBytesToCopy;
|
|
|
|
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
|
|
NdisChainBufferAtFront(ndisPacket, NdisBuffer);
|
|
|
|
//
|
|
// See if the response was too big (we can complete the
|
|
// request here since we still reference it).
|
|
//
|
|
|
|
if ((ResponseLength > ResponseBytesToCopy) ||
|
|
(UiFrame->Data2High & 0x40)) {
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
|
|
RemoveEntryList (&Request->Linkage);
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
receiveTag->CompleteReceive = TRUE;
|
|
receiveTag->EndOfMessage = FALSE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If we are done, complete the packet, otherwise send off
|
|
// the next request (unless it is a pre-2.1 response).
|
|
//
|
|
|
|
if ((UiFrame->Data1 > 0) && (UiFrame->Data2High & 0x80)) {
|
|
|
|
UCHAR TempSR[MAX_SOURCE_ROUTING];
|
|
PUCHAR ResponseSR;
|
|
|
|
receiveTag->CompleteReceive = FALSE;
|
|
|
|
//
|
|
// Try to cancel the timer, no harm if we fail.
|
|
//
|
|
|
|
ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
|
|
if ((Request->Flags & REQUEST_FLAGS_TIMER) != 0) {
|
|
|
|
Request->Flags &= ~REQUEST_FLAGS_TIMER;
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
if (KeCancelTimer (&Request->Timer)) {
|
|
NbfDereferenceRequest ("Status Response: stop timer", Request, RREF_TIMER);
|
|
}
|
|
|
|
} else {
|
|
RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
|
|
}
|
|
|
|
Request->Retries = DeviceContext->GeneralRetries;
|
|
|
|
//
|
|
// Send a STATUS_QUERY directed.
|
|
//
|
|
|
|
if (SourceRouting != NULL) {
|
|
|
|
RtlCopyMemory(
|
|
TempSR,
|
|
SourceRouting,
|
|
SourceRoutingLength);
|
|
|
|
MacCreateNonBroadcastReplySR(
|
|
&DeviceContext->MacInfo,
|
|
TempSR,
|
|
SourceRoutingLength,
|
|
&ResponseSR);
|
|
|
|
} else {
|
|
|
|
ResponseSR = NULL;
|
|
|
|
}
|
|
|
|
NbfSendStatusQuery(
|
|
DeviceContext,
|
|
Request,
|
|
SourceAddress,
|
|
ResponseSR,
|
|
SourceRoutingLength);
|
|
|
|
} else {
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
|
|
RemoveEntryList (&Request->Linkage);
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
receiveTag->CompleteReceive = TRUE;
|
|
receiveTag->EndOfMessage = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Now do the actual data transfer.
|
|
//
|
|
|
|
if (DeviceContext->NdisBindingHandle) {
|
|
|
|
NdisTransferData (
|
|
&ndisStatus,
|
|
DeviceContext->NdisBindingHandle,
|
|
ReceiveContext,
|
|
DeviceContext->MacInfo.TransferDataOffset +
|
|
3 + sizeof(NBF_HDR_CONNECTIONLESS),
|
|
ResponseBytesToCopy,
|
|
ndisPacket,
|
|
(PUINT)&ndisBytesTransferred);
|
|
}
|
|
else {
|
|
ndisStatus = STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
if (ndisStatus != NDIS_STATUS_PENDING) {
|
|
|
|
NbfTransferDataComplete(
|
|
(NDIS_HANDLE)DeviceContext,
|
|
ndisPacket,
|
|
ndisStatus,
|
|
ndisBytesTransferred);
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} /* NbfProcessStatusResponse */
|
|
|
|
|
|
NTSTATUS
|
|
NbfTdiSetInformation(
|
|
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); // prevent compiler warnings
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
} /* NbfTdiQueryInformation */
|
|
|
|
#if 0
|
|
|
|
NTSTATUS
|
|
NbfQueryInfoEndpoint(
|
|
IN PTP_ENDPOINT Endpoint,
|
|
IN PTDI_REQ_QUERY_INFORMATION TdiRequest,
|
|
IN ULONG TdiRequestLength,
|
|
OUT PTDI_ENDPOINT_INFO InfoBuffer,
|
|
IN ULONG InfoBufferLength,
|
|
OUT PULONG InformationSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns information for the specified endpoint.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - Pointer to transport endpoint context.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
InfoBuffer - Pointer to output buffer to return information into.
|
|
|
|
InfoBufferLength - Length of output buffer.
|
|
|
|
InformationSize - Pointer to ulong where actual size of returned
|
|
information is to be stored.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL oldirql;
|
|
|
|
TdiRequest, TdiRequestLength; // prevent compiler warnings
|
|
|
|
if (InfoBufferLength < sizeof (TDI_ENDPOINT_INFO)) {
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK (&Endpoint->SpinLock, &oldirql);
|
|
|
|
*InfoBuffer = Endpoint->Information; // structure copy.
|
|
|
|
RELEASE_SPIN_LOCK (&Endpoint->SpinLock, oldirql);
|
|
|
|
*InformationSize = sizeof (Endpoint->Information);
|
|
|
|
return STATUS_SUCCESS;
|
|
} /* NbfQueryInfoEndpoint */
|
|
|
|
|
|
NTSTATUS
|
|
NbfQueryInfoConnection(
|
|
IN PTP_CONNECTION Connection,
|
|
IN PTDI_REQUEST_KERNEL TdiRequest,
|
|
IN ULONG TdiRequestLength,
|
|
OUT PTDI_CONNECTION_INFO InfoBuffer,
|
|
IN ULONG InfoBufferLength,
|
|
OUT PULONG InformationSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns information for the specified connection.
|
|
|
|
Arguments:
|
|
|
|
Connection - Pointer to transport connection object.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
InfoBuffer - Pointer to output buffer to return information into.
|
|
|
|
InfoBufferLength - Length of output buffer.
|
|
|
|
InformationSize - Pointer to ulong where actual size of returned
|
|
information is to be stored.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL oldirql;
|
|
|
|
TdiRequest, TdiRequestLength; // prevent compiler warnings
|
|
|
|
if (InfoBufferLength < sizeof (TDI_CONNECTION_INFO)) {
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
|
|
|
|
*InfoBuffer = Connection->Information; // structure copy.
|
|
|
|
RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
|
|
|
|
*InformationSize = sizeof (Connection->Information);
|
|
|
|
return STATUS_SUCCESS;
|
|
} /* NbfQueryInfoConnection */
|
|
|
|
|
|
NTSTATUS
|
|
NbfQueryInfoAddress(
|
|
IN PTP_ADDRESS Address,
|
|
IN PTDI_REQUEST_KERNEL TdiRequest,
|
|
IN ULONG TdiRequestLength,
|
|
OUT PTDI_ADDRESS_INFO InfoBuffer,
|
|
IN ULONG InfoBufferLength,
|
|
OUT PULONG InformationSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns information for the specified address. We
|
|
don't acquire a spinlock in this routine because there are no statistics
|
|
which must be read atomically.
|
|
|
|
Arguments:
|
|
|
|
Address - Pointer to transport address object.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
InfoBuffer - Pointer to output buffer to return information into.
|
|
|
|
InfoBufferLength - Length of output buffer.
|
|
|
|
InformationSize - Pointer to ulong where actual size of returned
|
|
information is to be stored.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
SHORT i;
|
|
PSZ p, q;
|
|
|
|
TdiRequest, TdiRequestLength; // prevent compiler warnings
|
|
|
|
//
|
|
// Calculate whether his buffer is big enough to return the entire
|
|
// information. The total size of the address information is the
|
|
// size of the fixed part, plus the size of the variable-length flat
|
|
// string in the NETWORK_NAME component of the TRANSPORT_ADDRESS
|
|
// component.
|
|
//
|
|
|
|
if (InfoBufferLength <
|
|
sizeof (TDI_ADDRESS_INFO) +
|
|
Address->NetworkName.Length)
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
//
|
|
// Copy both the fixed part of the address information, and the variable
|
|
// part. The variable part comes from the NETWORK_NAME component of the
|
|
// TRANSPORT_ADDRESS structure. This component contains a FLAT_STRING,
|
|
// which is of variable length.
|
|
//
|
|
|
|
InfoBuffer->Address.AddressComponents = Address->AddressComponents;
|
|
InfoBuffer->Address.Tsap = Address->Tsap;
|
|
|
|
InfoBuffer->Address.NetworkName.Name.Length =
|
|
Address->NetworkName.Length;
|
|
|
|
p = Address->NetworkName.Buffer; // p = ptr, source string.
|
|
q = InfoBuffer->Address.NetworkName.Name.Buffer; // q = ptr, dest string.
|
|
for (i=0; i<InfoBuffer->Address.NetworkName.Name.Length; i++) {
|
|
*(q++) = *(p++);
|
|
}
|
|
|
|
*InformationSize = sizeof (TDI_ADDRESS_INFO) +
|
|
Address->NetworkName.Length;
|
|
|
|
return STATUS_SUCCESS;
|
|
} /* NbfQueryInfoAddress */
|
|
|
|
|
|
NTSTATUS
|
|
NbfQueryInfoProvider(
|
|
IN PDEVICE_CONTEXT Provider,
|
|
IN PTDI_REQUEST_KERNEL TdiRequest,
|
|
IN ULONG TdiRequestLength,
|
|
OUT PTDI_PROVIDER_INFO InfoBuffer,
|
|
IN ULONG InfoBufferLength,
|
|
OUT PULONG InformationSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns information for the transport provider.
|
|
|
|
Arguments:
|
|
|
|
Provider - Pointer to device context for provider.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
InfoBuffer - Pointer to output buffer to return information into.
|
|
|
|
InfoBufferLength - Length of output buffer.
|
|
|
|
InformationSize - Pointer to ulong where actual size of returned
|
|
information is to be stored.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL oldirql;
|
|
|
|
TdiRequest, TdiRequestLength; // prevent compiler warnings
|
|
|
|
if (InfoBufferLength < sizeof (TDI_PROVIDER_INFO)) {
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK (&Provider->SpinLock, &oldirql);
|
|
|
|
*InfoBuffer = Provider->Information; // structure copy.
|
|
|
|
RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
|
|
|
|
*InformationSize = sizeof (Provider->Information);
|
|
|
|
return STATUS_SUCCESS;
|
|
} /* NbfQueryInfoProvider */
|
|
|
|
|
|
NTSTATUS
|
|
NbfQueryInfoNetman(
|
|
IN PDEVICE_CONTEXT Provider,
|
|
IN PTDI_REQUEST_KERNEL TdiRequest,
|
|
IN ULONG TdiRequestLength,
|
|
OUT PTDI_NETMAN_INFO InfoBuffer,
|
|
IN ULONG InfoBufferLength,
|
|
OUT PULONG InformationSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns information for the specified network-managable
|
|
variable managed by the transport provider.
|
|
|
|
Arguments:
|
|
|
|
Provider - Pointer to device context for provider.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
InfoBuffer - Pointer to output buffer to return information into.
|
|
|
|
InfoBufferLength - Length of output buffer.
|
|
|
|
InformationSize - Pointer to ulong where actual size of returned
|
|
information is to be stored.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL oldirql;
|
|
PFLAT_STRING p;
|
|
PTP_VARIABLE v;
|
|
PTDI_NETMAN_VARIABLE n;
|
|
USHORT i;
|
|
ULONG NameOffset, ValueOffset;
|
|
|
|
TdiRequest, TdiRequestLength; // prevent compiler warnings
|
|
InfoBufferLength, InformationSize;
|
|
|
|
//
|
|
// check param lengths here.
|
|
//
|
|
|
|
ACQUIRE_SPIN_LOCK (&Provider->SpinLock, &oldirql);
|
|
NbfReferenceDeviceContext ("Query InfoNetMan", Provider, DCREF_QUERY_INFO);
|
|
for (v=Provider->NetmanVariables; v != NULL; v=v->Fwdlink) {
|
|
if (TdiRequest->Identification == v->VariableSerialNumber) {
|
|
|
|
//
|
|
// Return the variable information here.
|
|
//
|
|
|
|
NameOffset = sizeof (TDI_NETMAN_INFO);
|
|
ValueOffset = NameOffset + (sizeof (FLAT_STRING)-1) +
|
|
v->VariableName.Length;
|
|
|
|
InfoBuffer->VariableName = NameOffset;
|
|
InfoBuffer->VariableValue = ValueOffset;
|
|
|
|
//
|
|
// Copy the variable name to the user's buffer.
|
|
//
|
|
|
|
p = (PFLAT_STRING)((PUCHAR)InfoBuffer + NameOffset);
|
|
p->MaximumLength = v->VariableName.Length;
|
|
p->Length = v->VariableName.Length;
|
|
for (i=0; i<v->VariableName.Length; i++) {
|
|
p->Buffer [i] = v->VariableName.Buffer [i];
|
|
}
|
|
|
|
//
|
|
// Now copy the variable's contents to the user's buffer.
|
|
//
|
|
|
|
n = (PTDI_NETMAN_VARIABLE)((PUCHAR)InfoBuffer + ValueOffset);
|
|
n->VariableType = v->VariableType;
|
|
|
|
switch (v->VariableType) {
|
|
|
|
case NETMAN_VARTYPE_ULONG:
|
|
n->Value.LongValue = v->Value.LongValue;
|
|
break;
|
|
|
|
case NETMAN_VARTYPE_HARDWARE_ADDRESS:
|
|
n->Value.HardwareAddressValue =
|
|
v->Value.HardwareAddressValue;
|
|
break;
|
|
|
|
case NETMAN_VARTYPE_STRING:
|
|
p = &n->Value.StringValue;
|
|
p->MaximumLength = v->Value.StringValue.Length;
|
|
p->Length = v->Value.StringValue.Length;
|
|
for (i=0; i<v->Value.StringValue.Length; i++) {
|
|
p->Buffer [i] = v->Value.StringValue.Buffer [i];
|
|
}
|
|
|
|
} /* switch */
|
|
|
|
RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
|
|
NbfDereferenceDeviceContext ("Query InfoNetMan success", Provider, DCREF_QUERY_INFO);
|
|
return STATUS_SUCCESS;
|
|
} /* if */
|
|
} /* for */
|
|
|
|
RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
|
|
|
|
NbfDereferenceDeviceContext ("Query InfoNetMan no exist", Provider, DCREF_QUERY_INFO);
|
|
|
|
return STATUS_INVALID_INFO_CLASS; // variable does not exist.
|
|
} /* NbfQueryInfoNetman */
|
|
|
|
|
|
NTSTATUS
|
|
NbfSetInfoEndpoint(
|
|
IN PTP_ENDPOINT Endpoint,
|
|
IN PTDI_REQUEST_KERNEL TdiRequest,
|
|
IN ULONG TdiRequestLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets information for the specified endpoint.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - Pointer to transport endpoint context.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL oldirql;
|
|
PTDI_ENDPOINT_INFO InfoBuffer;
|
|
|
|
if (TdiRequestLength !=
|
|
sizeof (TDI_ENDPOINT_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
|
|
sizeof (TDI_INFO_BUFFER)) {
|
|
return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
|
|
}
|
|
|
|
InfoBuffer = (PTDI_ENDPOINT_INFO)&TdiRequest->InfoBuffer;
|
|
|
|
if ((InfoBuffer->MinimumLookaheadData <= NBF_MAX_LOOKAHEAD_DATA) ||
|
|
(InfoBuffer->MaximumLookaheadData <= NBF_MAX_LOOKAHEAD_DATA) ||
|
|
(InfoBuffer->MinimumLookaheadData > InfoBuffer->MaximumLookaheadData)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK (&Endpoint->SpinLock, &oldirql);
|
|
|
|
//
|
|
// Set minimum lookahead data size. This is the number of bytes of
|
|
// contiguous data that will be supplied to TDI_IND_RECEIVE and
|
|
// TDI_IND_RECEIVE_DATAGRAM event handlers at indication time.
|
|
//
|
|
|
|
Endpoint->Information.MinimumLookaheadData = InfoBuffer->MinimumLookaheadData;
|
|
|
|
//
|
|
// Set maximum lookahead data size. This is the number of bytes of
|
|
// contiguous data that will be supplied to TDI_IND_RECEIVE and
|
|
// TDI_IND_RECEIVE_DATAGRAM event handlers at indication time.
|
|
//
|
|
|
|
Endpoint->Information.MaximumLookaheadData = InfoBuffer->MaximumLookaheadData;
|
|
|
|
//
|
|
// Reset all the statistics to his new values.
|
|
//
|
|
|
|
Endpoint->Information.TransmittedTsdus = InfoBuffer->TransmittedTsdus;
|
|
Endpoint->Information.ReceivedTsdus = InfoBuffer->ReceivedTsdus;
|
|
Endpoint->Information.TransmissionErrors = InfoBuffer->TransmissionErrors;
|
|
Endpoint->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
|
|
Endpoint->Information.PriorityLevel = InfoBuffer->PriorityLevel;
|
|
Endpoint->Information.SecurityLevel = InfoBuffer->SecurityLevel;
|
|
Endpoint->Information.SecurityCompartment = InfoBuffer->SecurityCompartment;
|
|
|
|
//
|
|
// The State and Event fields are read-only, so we DON'T set them here.
|
|
//
|
|
|
|
RELEASE_SPIN_LOCK (&Endpoint->SpinLock, oldirql);
|
|
|
|
return STATUS_SUCCESS;
|
|
} /* NbfSetInfoEndpoint */
|
|
|
|
|
|
NTSTATUS
|
|
NbfSetInfoAddress(
|
|
IN PTP_ADDRESS Address,
|
|
IN PTDI_REQUEST_KERNEL TdiRequest,
|
|
IN ULONG TdiRequestLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets information for the specified address. Currently,
|
|
all the user-visible fields in the transport address object are read-only.
|
|
|
|
Arguments:
|
|
|
|
Address - Pointer to transport address object.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
Address, TdiRequest, TdiRequestLength; // prevent compiler warnings
|
|
|
|
return STATUS_SUCCESS;
|
|
} /* NbfSetInfoAddress */
|
|
|
|
|
|
NTSTATUS
|
|
NbfSetInfoConnection(
|
|
IN PTP_CONNECTION Connection,
|
|
IN PTDI_REQUEST_KERNEL TdiRequest,
|
|
IN ULONG TdiRequestLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets information for the specified connection.
|
|
|
|
Arguments:
|
|
|
|
Connection - Pointer to transport connection object.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL oldirql;
|
|
PTDI_CONNECTION_INFO InfoBuffer;
|
|
|
|
if (TdiRequestLength !=
|
|
sizeof (TDI_CONNECTION_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
|
|
sizeof (TDI_INFO_BUFFER)) {
|
|
return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
|
|
}
|
|
|
|
InfoBuffer = (PTDI_CONNECTION_INFO)&TdiRequest->InfoBuffer;
|
|
|
|
ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
|
|
|
|
//
|
|
// Reset all the statistics to his new values.
|
|
//
|
|
|
|
Connection->Information.TransmittedTsdus = InfoBuffer->TransmittedTsdus;
|
|
Connection->Information.ReceivedTsdus = InfoBuffer->ReceivedTsdus;
|
|
Connection->Information.TransmissionErrors = InfoBuffer->TransmissionErrors;
|
|
Connection->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
|
|
|
|
//
|
|
// The State and Event fields are read-only, so we DON'T set them here.
|
|
//
|
|
|
|
RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
|
|
|
|
return STATUS_SUCCESS;
|
|
} /* NbfSetInfoConnection */
|
|
|
|
|
|
NTSTATUS
|
|
NbfSetInfoProvider(
|
|
IN PDEVICE_CONTEXT Provider,
|
|
IN PTDI_REQUEST_KERNEL TdiRequest,
|
|
IN ULONG TdiRequestLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets information for the specified transport provider.
|
|
|
|
Arguments:
|
|
|
|
Provider - Pointer to device context.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL oldirql;
|
|
PTDI_PROVIDER_INFO InfoBuffer;
|
|
|
|
if (TdiRequestLength !=
|
|
sizeof (TDI_PROVIDER_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
|
|
sizeof (TDI_INFO_BUFFER)) {
|
|
return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
|
|
}
|
|
|
|
InfoBuffer = (PTDI_PROVIDER_INFO)&TdiRequest->InfoBuffer;
|
|
|
|
//
|
|
// By changing the service flags the caller can request additional
|
|
// or fewer services on the fly. Make sure that he is requesting
|
|
// services we can provide, or else fail the request.
|
|
//
|
|
|
|
if (InfoBuffer->ServiceFlags & ~NBF_SERVICE_FLAGS) {
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK (&Provider->SpinLock, &oldirql);
|
|
|
|
//
|
|
// Reset all the statistics to his new values.
|
|
//
|
|
|
|
Provider->Information.TransmittedTsdus = InfoBuffer->TransmittedTsdus;
|
|
Provider->Information.ReceivedTsdus = InfoBuffer->ReceivedTsdus;
|
|
Provider->Information.TransmissionErrors = InfoBuffer->TransmissionErrors;
|
|
Provider->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
|
|
Provider->Information.DiscardedFrames = InfoBuffer->DiscardedFrames;
|
|
Provider->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
|
|
Provider->Information.OversizeTsdusReceived = InfoBuffer->OversizeTsdusReceived;
|
|
Provider->Information.UndersizeTsdusReceived = InfoBuffer->UndersizeTsdusReceived;
|
|
Provider->Information.MulticastTsdusReceived = InfoBuffer->MulticastTsdusReceived;
|
|
Provider->Information.BroadcastTsdusReceived = InfoBuffer->BroadcastTsdusReceived;
|
|
Provider->Information.MulticastTsdusTransmitted = InfoBuffer->MulticastTsdusTransmitted;
|
|
Provider->Information.BroadcastTsdusTransmitted = InfoBuffer->BroadcastTsdusTransmitted;
|
|
Provider->Information.SendTimeouts = InfoBuffer->SendTimeouts;
|
|
Provider->Information.ReceiveTimeouts = InfoBuffer->ReceiveTimeouts;
|
|
Provider->Information.ConnectionIndicationsReceived = InfoBuffer->ConnectionIndicationsReceived;
|
|
Provider->Information.ConnectionIndicationsAccepted = InfoBuffer->ConnectionIndicationsAccepted;
|
|
Provider->Information.ConnectionsInitiated = InfoBuffer->ConnectionsInitiated;
|
|
Provider->Information.ConnectionsAccepted = InfoBuffer->ConnectionsAccepted;
|
|
|
|
//
|
|
// The following fields are read-only, so we DON'T set them here:
|
|
// Version, MaxTsduSize, MaxConnectionUserData, MinimumLookaheadData,
|
|
// MaximumLookaheadData.
|
|
//
|
|
|
|
RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
|
|
|
|
return STATUS_SUCCESS;
|
|
} /* NbfSetInfoProvider */
|
|
|
|
|
|
NTSTATUS
|
|
NbfSetInfoNetman(
|
|
IN PDEVICE_CONTEXT Provider,
|
|
IN PTDI_REQ_SET_INFORMATION TdiRequest,
|
|
IN ULONG TdiRequestLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets information for the specified transport provider's
|
|
network-managable variable.
|
|
|
|
Arguments:
|
|
|
|
Provider - Pointer to device context.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTDI_NETMAN_INFO InfoBuffer;
|
|
|
|
Provider; // prevent compiler warnings
|
|
|
|
if (TdiRequestLength !=
|
|
sizeof (TDI_NETMAN_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
|
|
sizeof (TDI_INFO_BUFFER)) {
|
|
return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
|
|
}
|
|
|
|
InfoBuffer = (PTDI_NETMAN_INFO)&TdiRequest->InfoBuffer;
|
|
|
|
//
|
|
// set the network-managable variable here.
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
} /* NbfSetInfoNetman */
|
|
|
|
|
|
NTSTATUS
|
|
NbfTdiQueryInformation(
|
|
IN PTP_ENDPOINT Endpoint,
|
|
IN PTDI_REQ_QUERY_INFORMATION TdiRequest,
|
|
IN ULONG TdiRequestLength,
|
|
OUT PTDI_INFO_BUFFER InfoBuffer,
|
|
IN ULONG InfoBufferLength,
|
|
OUT PULONG InformationSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the TdiQueryInformation request for the transport
|
|
provider.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - Pointer to transport endpoint context.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
InfoBuffer - Pointer to output buffer to return information into.
|
|
|
|
InfoBufferLength - Length of output buffer.
|
|
|
|
InformationSize - Pointer to ulong where actual size of returned
|
|
information is to be stored.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PTP_CONNECTION Connection;
|
|
|
|
switch (TdiRequest->InformationClass) {
|
|
|
|
//
|
|
// ENDPOINT information: return information about the endpoint
|
|
// to which this request was submitted.
|
|
//
|
|
|
|
case TDI_INFO_CLASS_ENDPOINT:
|
|
Status = NbfQueryInfoEndpoint (
|
|
Endpoint,
|
|
TdiRequest,
|
|
TdiRequestLength,
|
|
(PTDI_ENDPOINT_INFO)InfoBuffer,
|
|
InfoBufferLength,
|
|
InformationSize);
|
|
break;
|
|
|
|
//
|
|
// CONNECTION information: return information about a connection
|
|
// that is associated with the endpoint on which this request was
|
|
// submitted.
|
|
//
|
|
|
|
case TDI_INFO_CLASS_CONNECTION:
|
|
// This causes a connection reference which is removed below.
|
|
Connection = NbfLookupConnectionById (
|
|
Endpoint,
|
|
TdiRequest->Identification);
|
|
if (Connection == NULL) {
|
|
Status = STATUS_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
Status = NbfQueryInfoConnection (
|
|
Connection,
|
|
TdiRequest,
|
|
TdiRequestLength,
|
|
(PTDI_CONNECTION_INFO)InfoBuffer,
|
|
InfoBufferLength,
|
|
InformationSize);
|
|
|
|
NbfDereferenceConnection("Query Connection Info", Connection, CREF_BY_ID);
|
|
break;
|
|
|
|
//
|
|
// ADDRESS information: return information about the address object
|
|
// that is associated with the endpoint on which this request was
|
|
// submitted.
|
|
//
|
|
|
|
case TDI_INFO_CLASS_ADDRESS:
|
|
Status = NbfQueryInfoAddress (
|
|
Endpoint->BoundAddress,
|
|
TdiRequest,
|
|
TdiRequestLength,
|
|
(PTDI_ADDRESS_INFO)InfoBuffer,
|
|
InfoBufferLength,
|
|
InformationSize);
|
|
break;
|
|
|
|
//
|
|
// PROVIDER information: return information about the transport
|
|
// provider itself.
|
|
//
|
|
|
|
case TDI_INFO_CLASS_PROVIDER:
|
|
Status = NbfQueryInfoProvider (
|
|
Endpoint->BoundAddress->Provider,
|
|
TdiRequest,
|
|
TdiRequestLength,
|
|
(PTDI_PROVIDER_INFO)InfoBuffer,
|
|
InfoBufferLength,
|
|
InformationSize);
|
|
break;
|
|
|
|
//
|
|
// NETMAN information: return information about the network-managable
|
|
// variables managed by the provider itself.
|
|
//
|
|
|
|
case TDI_INFO_CLASS_NETMAN:
|
|
Status = NbfQueryInfoNetman (
|
|
Endpoint->BoundAddress->Provider,
|
|
TdiRequest,
|
|
TdiRequestLength,
|
|
(PTDI_NETMAN_INFO)InfoBuffer,
|
|
InfoBufferLength,
|
|
InformationSize);
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_INVALID_INFO_CLASS;
|
|
|
|
} /* switch */
|
|
|
|
return Status;
|
|
} /* TdiQueryInformation */
|
|
|
|
|
|
NTSTATUS
|
|
TdiSetInformation(
|
|
IN PTP_ENDPOINT Endpoint,
|
|
IN PTDI_REQ_SET_INFORMATION TdiRequest,
|
|
IN ULONG TdiRequestLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the TdiSetInformation request for the transport
|
|
provider.
|
|
|
|
Arguments:
|
|
|
|
Endpoint - Pointer to transport endpoint context.
|
|
|
|
TdiRequest - Pointer to request buffer.
|
|
|
|
TdiRequestLength - Length of request buffer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PTP_CONNECTION Connection;
|
|
|
|
switch (TdiRequest->InformationClass) {
|
|
|
|
//
|
|
// ENDPOINT information: set information on the endpoint
|
|
// to which this request was submitted.
|
|
//
|
|
|
|
case TDI_INFO_CLASS_ENDPOINT:
|
|
Status = NbfSetInfoEndpoint (
|
|
Endpoint,
|
|
TdiRequest,
|
|
TdiRequestLength);
|
|
break;
|
|
|
|
//
|
|
// CONNECTION information: set information for a connection
|
|
// that is associated with the endpoint on which this request
|
|
// was submitted.
|
|
//
|
|
|
|
case TDI_INFO_CLASS_CONNECTION:
|
|
// This causes a connection reference which is removed below.
|
|
Connection = NbfLookupConnectionById (
|
|
Endpoint,
|
|
TdiRequest->Identification);
|
|
if (Connection == NULL) {
|
|
Status = STATUS_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
Status = NbfSetInfoConnection (
|
|
Connection,
|
|
TdiRequest,
|
|
TdiRequestLength);
|
|
|
|
NbfDereferenceConnection("Set Connection Info", Connection, CREF_BY_ID);
|
|
break;
|
|
|
|
//
|
|
// ADDRESS information: set information for the address object
|
|
// that is associated with the endpoint on which this request
|
|
// was submitted.
|
|
//
|
|
|
|
case TDI_INFO_CLASS_ADDRESS:
|
|
Status = NbfSetInfoAddress (
|
|
Endpoint->BoundAddress,
|
|
TdiRequest,
|
|
TdiRequestLength);
|
|
break;
|
|
|
|
//
|
|
// PROVIDER information: set information for the transport
|
|
// provider itself.
|
|
//
|
|
|
|
case TDI_INFO_CLASS_PROVIDER:
|
|
Status = NbfSetInfoProvider (
|
|
Endpoint->BoundAddress->Provider,
|
|
TdiRequest,
|
|
TdiRequestLength);
|
|
break;
|
|
|
|
//
|
|
// NETMAN information: set information for the network-managable
|
|
// variables managed by the provider itself.
|
|
//
|
|
|
|
case TDI_INFO_CLASS_NETMAN:
|
|
Status = NbfSetInfoNetman (
|
|
Endpoint->BoundAddress->Provider,
|
|
TdiRequest,
|
|
TdiRequestLength);
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_INVALID_INFO_CLASS;
|
|
|
|
} /* switch */
|
|
|
|
return Status;
|
|
} /* TdiSetInformation */
|
|
|
|
#endif
|