summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/nbf/info.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/nbf/info.c')
-rw-r--r--private/ntos/tdi/nbf/info.c3487
1 files changed, 3487 insertions, 0 deletions
diff --git a/private/ntos/tdi/nbf/info.c b/private/ntos/tdi/nbf/info.c
new file mode 100644
index 000000000..f1cf8890b
--- /dev/null
+++ b/private/ntos/tdi/nbf/info.c
@@ -0,0 +1,3487 @@
+/*++
+
+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 UNALIGNED * RemoteAddress;
+ struct {
+ ULONG ActivityCount;
+ TA_NETBIOS_ADDRESS TaAddressBuffer;
+ } AddressInfo;
+ PTRANSPORT_ADDRESS TaAddress;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ BOOLEAN UsedConnection;
+ PLIST_ENTRY p;
+ KIRQL oldirql;
+
+ //
+ // 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.
+ //
+
+ 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),
+ ' FBN');
+
+ 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,
+ &(Irp->IoStatus.Information));
+
+ 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,
+ &Irp->IoStatus.Information);
+
+ 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),
+ ' FBN');
+ 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);
+
+ 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:
+
+ //
+ // BUGBUG: 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)),
+ ' FBN');
+
+ 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,
+ &(Irp->IoStatus.Information));
+
+ 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,
+ ' FBN');
+
+ 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,
+ ' FBN');
+
+ 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,
+ &Irp->IoStatus.Information);
+
+ 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,
+ ' FBN');
+
+ 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,
+ &Irp->IoStatus.Information);
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ DatagramInfo.MaximumDatagramBytes = 0;
+ DatagramInfo.MaximumDatagramCount = 0;
+
+ status = TdiCopyBufferToMdl (
+ &DatagramInfo,
+ 0,
+ sizeof(DatagramInfo),
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+ 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;
+ }
+
+ // 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;
+
+} /* 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,
+ ' FBN');
+
+ 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 UNALIGNED * 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 += 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 UNALIGNED * 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.
+ //
+
+ NdisTransferData (
+ &ndisStatus,
+ DeviceContext->NdisBindingHandle,
+ ReceiveContext,
+ DeviceContext->MacInfo.TransferDataOffset +
+ 3 + sizeof(NBF_HDR_CONNECTIONLESS),
+ ResponseBytesToCopy,
+ ndisPacket,
+ (PUINT)&ndisBytesTransferred);
+
+ 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;
+
+ //
+ // BUGBUG: 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