windows-nt/Source/XPSP1/NT/net/nwlink/nb/query.c
2020-09-26 16:20:57 +08:00

1839 lines
52 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989-1993 Microsoft Corporation
Module Name:
query.c
Abstract:
This module contains code which performs the following TDI services:
o TdiQueryInformation
o TdiSetInformation
Environment:
Kernel mode
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Remove the warning -- this is defined in windef also.
//
#ifdef FAR
#undef FAR
#endif
#include <windef.h>
#include <nb30.h>
//
// Useful macro to obtain the total length of a buffer chain.
// Make this use NDIS macros ?
//
#define NbiGetBufferChainLength(Buffer, Length) { \
PNDIS_BUFFER _Buffer = (Buffer); \
*(Length) = 0; \
while (_Buffer) { \
*(Length) += MmGetMdlByteCount(_Buffer); \
_Buffer = _Buffer->Next; \
} \
}
NTSTATUS
NbiTdiQueryInformation(
IN PDEVICE Device,
IN PREQUEST Request
)
/*++
Routine Description:
This routine performs the TdiQueryInformation request for the transport
provider.
Arguments:
Request - the request for the operation.
Return Value:
The status of operation.
--*/
{
NTSTATUS Status;
PTDI_REQUEST_KERNEL_QUERY_INFORMATION Query;
PADDRESS_FILE AddressFile;
PADDRESS Address;
PCONNECTION Connection;
union {
struct {
ULONG ActivityCount;
TA_NETBIOS_ADDRESS NbiAddress;
} AddressInfo;
TA_NETBIOS_ADDRESS BroadcastAddress;
TDI_ADDRESS_IPX IpxAddress;
TDI_DATAGRAM_INFO DatagramInfo;
struct {
FIND_NAME_HEADER Header;
FIND_NAME_BUFFER Buffer;
} FindNameInfo;
} TempBuffer;
IPX_SOURCE_ROUTING_INFO SourceRoutingInfo;
PADAPTER_STATUS AdapterStatus;
BOOLEAN RemoteAdapterStatus;
TDI_ADDRESS_NETBIOS * RemoteAddress;
ULONG TargetBufferLength;
ULONG ActualBytesCopied;
ULONG AdapterStatusLength;
ULONG ValidStatusLength;
ULONG ElementSize, TransportAddressSize;
PTRANSPORT_ADDRESS TransportAddress;
TA_ADDRESS * CurAddress;
PNETBIOS_CACHE CacheName;
FIND_NAME_HEADER UNALIGNED * FindNameHeader = NULL;
UINT FindNameBufferLength;
NTSTATUS QueryStatus;
CTELockHandle LockHandle;
PLIST_ENTRY p;
BOOLEAN UsedConnection;
UINT i;
//
// what type of status do we want?
//
Query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
switch (Query->QueryType) {
case TDI_QUERY_ADDRESS_INFO:
//
// The caller wants the exact address value.
//
if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
#if defined(_PNP_POWER)
Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
#else
Status = NbiVerifyAddressFile (AddressFile);
#endif _PNP_POWER
if (!NT_SUCCESS(Status)) {
break;
}
UsedConnection = FALSE;
} else if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE) {
Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
Status = NbiVerifyConnection (Connection);
if (!NT_SUCCESS(Status)) {
break;
}
if (!(AddressFile = Connection->AddressFile))
{
Status = STATUS_INVALID_ADDRESS;
break;
}
UsedConnection = TRUE;
} else {
Status = STATUS_INVALID_ADDRESS;
break;
}
Address = AddressFile->Address;
NB_DEBUG2 (QUERY, ("Query address info on %lx\n", AddressFile));
TempBuffer.AddressInfo.ActivityCount = 0;
NB_GET_LOCK (&Address->Lock, &LockHandle);
for (p = Address->AddressFileDatabase.Flink;
p != &Address->AddressFileDatabase;
p = p->Flink) {
if (CONTAINING_RECORD (p, ADDRESS_FILE, Linkage)->State == ADDRESSFILE_STATE_OPEN) {
++TempBuffer.AddressInfo.ActivityCount;
}
}
NB_FREE_LOCK (&Address->Lock, LockHandle);
TdiBuildNetbiosAddress(
AddressFile->Address->NetbiosAddress.NetbiosName,
(BOOLEAN)(AddressFile->Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP),
&TempBuffer.AddressInfo.NbiAddress);
Status = TdiCopyBufferToMdl(
&TempBuffer.AddressInfo,
0,
sizeof(ULONG) + sizeof(TA_NETBIOS_ADDRESS),
REQUEST_NDIS_BUFFER(Request),
0,
&ActualBytesCopied);
REQUEST_INFORMATION(Request) = ActualBytesCopied;
if (UsedConnection) {
NbiDereferenceConnection (Connection, CREF_VERIFY);
} else {
NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
}
break;
case TDI_QUERY_CONNECTION_INFO:
//
// Connection info is queried on a connection,
// verify this.
//
Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
Status = NbiVerifyConnection (Connection);
if (!NT_SUCCESS (Status)) {
return Status;
}
if (Connection->State != CONNECTION_STATE_ACTIVE) {
Status = STATUS_INVALID_CONNECTION;
} else {
//
// Assume 50 ms of delay for every hop after the
// first. The delay is returned as a negative number.
//
if (Connection->HopCount > 1) {
Connection->ConnectionInfo.Delay.HighPart = (ULONG)-1;
Connection->ConnectionInfo.Delay.LowPart =
-((Connection->HopCount-1) * 50 * MILLISECONDS);
} else {
Connection->ConnectionInfo.Delay.HighPart = 0;
Connection->ConnectionInfo.Delay.LowPart = 0;
}
//
// We have tick count; to convert to bytes/second we do:
//
// packet 576 bytes 18.21 ticks
// ---------------- * --------- * -----------
// tick_count ticks packet seconds
//
// to get 10489/tick_count = bytes/second. We
// double this because routers tend to
// overestimate it.
//
// Since tick_count has such a low granularity,
// a tick count of 1 gives us a throughput of
// only 84 kbps, which is much too low. In
// that case we return twice the link speed
// which is in 100 bps units; that corresponds
// to about 1/6 of our bandwidth in bytes/sec.
//
if (Connection->TickCount <= Connection->HopCount) {
Connection->ConnectionInfo.Throughput.QuadPart =
UInt32x32To64 (Connection->LineInfo.LinkSpeed, 2);
} else {
Connection->ConnectionInfo.Throughput.HighPart = 0;
Connection->ConnectionInfo.Throughput.LowPart =
20978 / (Connection->TickCount - Connection->HopCount);
}
Connection->ConnectionInfo.Unreliable = FALSE;
Status = TdiCopyBufferToMdl (
&Connection->ConnectionInfo,
0,
sizeof(TDI_CONNECTION_INFO),
REQUEST_NDIS_BUFFER(Request),
0,
&ActualBytesCopied);
REQUEST_INFORMATION(Request) = ActualBytesCopied;
}
NbiDereferenceConnection (Connection, CREF_VERIFY);
break;
case TDI_QUERY_PROVIDER_INFO:
NB_DEBUG2 (QUERY, ("Query provider info\n"));
Status = TdiCopyBufferToMdl (
&Device->Information,
0,
sizeof (TDI_PROVIDER_INFO),
REQUEST_NDIS_BUFFER(Request),
0,
&ActualBytesCopied);
REQUEST_INFORMATION(Request) = ActualBytesCopied;
break;
case TDI_QUERY_BROADCAST_ADDRESS:
//
// for this provider, the broadcast address is a zero byte name,
// contained in a Transport address structure.
//
NB_DEBUG2 (QUERY, ("Query broadcast address\n"));
TempBuffer.BroadcastAddress.TAAddressCount = 1;
TempBuffer.BroadcastAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
TempBuffer.BroadcastAddress.Address[0].AddressLength = 0;
Status = TdiCopyBufferToMdl (
(PVOID)&TempBuffer.BroadcastAddress,
0L,
sizeof (TempBuffer.BroadcastAddress.TAAddressCount) +
sizeof (TempBuffer.BroadcastAddress.Address[0].AddressType) +
sizeof (TempBuffer.BroadcastAddress.Address[0].AddressLength),
REQUEST_NDIS_BUFFER(Request),
0,
&ActualBytesCopied);
REQUEST_INFORMATION(Request) = ActualBytesCopied;
break;
case TDI_QUERY_ADAPTER_STATUS:
//
// Determine if this is a local or remote query.
//
RemoteAdapterStatus = FALSE;
if (Query->RequestConnectionInformation != NULL) {
RemoteAddress = NbiParseTdiAddress(Query->RequestConnectionInformation->RemoteAddress, Query->RequestConnectionInformation->RemoteAddressLength, FALSE);
if (RemoteAddress == NULL) {
return STATUS_BAD_NETWORK_PATH;
}
#if defined(_PNP_POWER)
if ( !NbiFindAdapterAddress(
RemoteAddress->NetbiosName,
LOCK_NOT_ACQUIRED ) ) {
RemoteAdapterStatus = TRUE;
}
#else
if (!RtlEqualMemory(
RemoteAddress->NetbiosName,
Device->ReservedNetbiosName,
16)) {
RemoteAdapterStatus = TRUE;
}
#endif _PNP_POWER
}
if (RemoteAdapterStatus) {
//
// See if we have this name cached.
//
NB_GET_LOCK (&Device->Lock, &LockHandle);
Status = CacheFindName(
Device,
FindNameOther,
RemoteAddress->NetbiosName,
&CacheName);
if (Status == STATUS_PENDING) {
//
// A request for routes to this name has been
// sent out on the net, we queue up this status
// request and processing will be resumed when
// we get a response.
//
// The status field in the request will hold
// the cache entry for the remote. The information
// field will hold the remote netbios name while
// it is in the WaitingAdapterStatus queue, and
// will hold a timeout value while we it is in
// the ActiveAdapterStatus queue.
//
NB_DEBUG2 (QUERY, ("Queueing up adapter status %lx\n", Request));
NbiReferenceDevice (Device, DREF_STATUS_QUERY);
REQUEST_INFORMATION (Request) = (ULONG_PTR) RemoteAddress;
InsertTailList(
&Device->WaitingAdapterStatus,
REQUEST_LINKAGE (Request));
NB_FREE_LOCK (&Device->Lock, LockHandle);
} else if (Status == STATUS_SUCCESS) {
NB_DEBUG2 (QUERY, ("Found adapter status cached %lx\n", Request));
//
// We reference the cache name entry so it won't
// go away while we are using it.
//
REQUEST_STATUSPTR(Request) = (PVOID)CacheName;
++CacheName->ReferenceCount;
NbiReferenceDevice (Device, DREF_STATUS_QUERY);
REQUEST_INFORMATION (Request) = 0;
InsertTailList(
&Device->ActiveAdapterStatus,
REQUEST_LINKAGE (Request));
NB_FREE_LOCK (&Device->Lock, LockHandle);
NbiSendStatusQuery (Request);
Status = STATUS_PENDING;
} else {
if (Status != STATUS_INSUFFICIENT_RESOURCES) {
Status = STATUS_IO_TIMEOUT;
}
REQUEST_INFORMATION (Request) = 0;
NB_FREE_LOCK (&Device->Lock, LockHandle);
}
} else {
//
// Local adapter status.
//
NbiGetBufferChainLength (REQUEST_NDIS_BUFFER(Request), &TargetBufferLength);
Status = NbiStoreAdapterStatus(
TargetBufferLength,
1, // NIC ID, was 0, changed to 1 for Bug #18026
// because for NicId = 0, Ipx returns virtual
// address. Netbios uses that to register the
// name (00...01) and fails.
&AdapterStatus,
&AdapterStatusLength,
&ValidStatusLength);
if (Status != STATUS_INSUFFICIENT_RESOURCES) {
//
// This should succeed since we know the length
// will fit.
//
(VOID)TdiCopyBufferToMdl(
AdapterStatus,
0,
ValidStatusLength,
REQUEST_NDIS_BUFFER(Request),
0,
&ActualBytesCopied);
REQUEST_INFORMATION(Request) = ActualBytesCopied;
NbiFreeMemory (AdapterStatus, AdapterStatusLength, MEMORY_STATUS, "Adapter Status");
}
}
break;
case TDI_QUERY_FIND_NAME:
//
// Check that there is a valid Netbios remote address.
//
if ((Query->RequestConnectionInformation == NULL) ||
((RemoteAddress = NbiParseTdiAddress(Query->RequestConnectionInformation->RemoteAddress, Query->RequestConnectionInformation->RemoteAddressLength, FALSE)) == NULL)) {
return STATUS_BAD_NETWORK_PATH;
}
//
// We assume the entire request buffer is in the first
// piece of the MDL chain.
// Make sure there is room for at least the header.
//
NdisQueryBufferSafe (REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength,
HighPagePriority);
if ((!FindNameHeader) ||
(FindNameBufferLength < sizeof(FIND_NAME_HEADER))) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// See if we have this name cached. We specify that this is
// a netbios name query, so this will only succeed if this is a
// unique name -- for a group name it will queue up a find
// name query and when we get the response we will fill in
// the request's buffer based on it.
//
NB_GET_LOCK (&Device->Lock, &LockHandle);
Status = CacheFindName(
Device,
FindNameNetbiosFindName,
RemoteAddress->NetbiosName,
&CacheName);
if (Status == STATUS_PENDING) {
//
// A request for routes to this name has been
// sent out on the net, we queue up this find
// name request and processing will be resumed when
// we get a response.
//
// The information field will hold the remote
// netbios name while it is in the WaitingNetbiosFindName
// queue. The status will hold the current status --
// initially failure, then success, then overflow
// if the buffer is too small.
//
NB_DEBUG2 (QUERY, ("Queueing up find name %lx\n", Request));
NbiReferenceDevice (Device, DREF_NB_FIND_NAME);
FindNameHeader->node_count = 0;
FindNameHeader->reserved = 0;
FindNameHeader->unique_group = 0;
REQUEST_INFORMATION (Request) = (ULONG_PTR)RemoteAddress;
//
// Assume it fails, we update the status to
// SUCCESS or BUFFER_OVERFLOW if needed.
//
REQUEST_STATUS (Request) = STATUS_IO_TIMEOUT;
InsertTailList(
&Device->WaitingNetbiosFindName,
REQUEST_LINKAGE (Request));
NB_FREE_LOCK (&Device->Lock, LockHandle);
} else if (Status == STATUS_SUCCESS) {
NB_DEBUG2 (QUERY, ("Found find name cached %lx\n", Request));
//
// We don't need to reference the cache entry since
// we only use it here with the lock still held.
//
//
// Query the local address, which we will return as
// the destination address of this query. Since we
// use TempBuffer.IpxAddress for this query, we have
// to immediately copy it to its correct place in
// TempBuffer.FindNameInfo.Buffer.
//
#if defined(_PNP_POWER)
if( (*Device->Bind.QueryHandler)( // Check return code
IPX_QUERY_IPX_ADDRESS,
&CacheName->Networks[0].LocalTarget.NicHandle,
&TempBuffer.IpxAddress,
sizeof(TDI_ADDRESS_IPX),
NULL) != STATUS_SUCCESS ) {
NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_IPX_ADDRESS,
CacheName->Networks[0].LocalTarget.NicHandle.NicId ));
goto QueryFindNameFailed;
}
#else
(VOID)(*Device->Bind.QueryHandler)( // Check return code
IPX_QUERY_IPX_ADDRESS,
CacheName->Networks[0].LocalTarget.NicId,
&TempBuffer.IpxAddress,
sizeof(TDI_ADDRESS_IPX),
NULL);
#endif _PNP_POWER
RtlMoveMemory (TempBuffer.FindNameInfo.Buffer.destination_addr, TempBuffer.IpxAddress.NodeAddress, 6);
TempBuffer.FindNameInfo.Buffer.access_control = 0x10; // standard token-ring values
TempBuffer.FindNameInfo.Buffer.frame_control = 0x40;
RtlCopyMemory (TempBuffer.FindNameInfo.Buffer.source_addr, CacheName->FirstResponse.NodeAddress, 6);
//
// Query source routing information about this remote, if any.
//
SourceRoutingInfo.Identifier = IDENTIFIER_NB;
RtlCopyMemory (SourceRoutingInfo.RemoteAddress, CacheName->FirstResponse.NodeAddress, 6);
QueryStatus = (*Device->Bind.QueryHandler)(
IPX_QUERY_SOURCE_ROUTING,
#if defined(_PNP_POWER)
&CacheName->Networks[0].LocalTarget.NicHandle,
#else
CacheName->Networks[0].LocalTarget.NicId,
#endif _PNP_POWER
&SourceRoutingInfo,
sizeof(IPX_SOURCE_ROUTING_INFO),
NULL);
RtlZeroMemory(TempBuffer.FindNameInfo.Buffer.routing_info, 18);
if (QueryStatus != STATUS_SUCCESS) {
SourceRoutingInfo.SourceRoutingLength = 0;
} else if (SourceRoutingInfo.SourceRoutingLength > 0) {
RtlMoveMemory(
TempBuffer.FindNameInfo.Buffer.routing_info,
SourceRoutingInfo.SourceRouting,
SourceRoutingInfo.SourceRoutingLength);
}
TempBuffer.FindNameInfo.Buffer.length = (UCHAR)(14 + SourceRoutingInfo.SourceRoutingLength);
TempBuffer.FindNameInfo.Header.node_count = 1;
TempBuffer.FindNameInfo.Header.reserved = 0;
TempBuffer.FindNameInfo.Header.unique_group = 0; // unique
NB_FREE_LOCK (&Device->Lock, LockHandle);
//
// 33 is sizeof(FIND_NAME_BUFFER) without the padding.
//
Status = TdiCopyBufferToMdl (
(PVOID)&TempBuffer.FindNameInfo,
0,
sizeof(FIND_NAME_HEADER) + 33,
REQUEST_NDIS_BUFFER(Request),
0,
&ActualBytesCopied);
REQUEST_INFORMATION(Request) = ActualBytesCopied;
} else {
#if defined(_PNP_POWER)
QueryFindNameFailed:
#endif _PNP_POWER
if (Status != STATUS_INSUFFICIENT_RESOURCES) {
Status = STATUS_IO_TIMEOUT;
}
REQUEST_INFORMATION (Request) = 0;
NB_FREE_LOCK (&Device->Lock, LockHandle);
}
break;
case TDI_QUERY_PROVIDER_STATISTICS:
//
// Keep track of more of these.
//
NB_DEBUG2 (QUERY, ("Query provider statistics\n"));
Status = TdiCopyBufferToMdl (
&Device->Statistics,
0,
FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
REQUEST_NDIS_BUFFER(Request),
0,
&ActualBytesCopied);
REQUEST_INFORMATION(Request) = ActualBytesCopied;
break;
case TDI_QUERY_DATAGRAM_INFO:
NB_DEBUG2 (QUERY, ("Query datagram info\n"));
TempBuffer.DatagramInfo.MaximumDatagramBytes = 0;
TempBuffer.DatagramInfo.MaximumDatagramCount = 0;
Status = TdiCopyBufferToMdl (
&TempBuffer.DatagramInfo,
0,
sizeof(TempBuffer.DatagramInfo),
REQUEST_NDIS_BUFFER(Request),
0,
&ActualBytesCopied);
REQUEST_INFORMATION(Request) = ActualBytesCopied;
break;
case TDI_QUERY_DATA_LINK_ADDRESS:
case TDI_QUERY_NETWORK_ADDRESS:{
#if defined(_PNP_POWER)
Status = (*Device->Bind.QueryHandler)( // Check return code
(Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS
? IPX_QUERY_DATA_LINK_ADDRESS
: IPX_QUERY_NETWORK_ADDRESS ),
NULL,
Request,
0,
NULL);
#else
ULONG TransportAddressAllocSize;
if (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
ElementSize = (2 * sizeof(USHORT)) + 6;
} else {
ElementSize = (2 * sizeof(USHORT)) + sizeof(TDI_ADDRESS_IPX);
}
// TransportAddress = CTEAllocMem(sizeof(int) + (ElementSize * Device->MaximumNicId));
TransportAddressAllocSize = sizeof(int) + ( ElementSize * Device->MaximumNicId);
TransportAddress = NbiAllocateMemory( TransportAddressAllocSize, MEMORY_QUERY, "Temp Query Allocation");
if (TransportAddress == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
TransportAddress->TAAddressCount = 0;
TransportAddressSize = sizeof(int);
CurAddress = (TA_ADDRESS UNALIGNED *)TransportAddress->Address;
for (i = 1; i <= Device->MaximumNicId; i++) {
Status = (*Device->Bind.QueryHandler)( // Check return code
IPX_QUERY_IPX_ADDRESS,
(USHORT)i,
&TempBuffer.IpxAddress,
sizeof(TDI_ADDRESS_IPX),
NULL);
if (Status != STATUS_SUCCESS) {
continue;
}
if (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
CurAddress->AddressLength = 6;
CurAddress->AddressType = TDI_ADDRESS_TYPE_UNSPEC;
RtlCopyMemory (CurAddress->Address, TempBuffer.IpxAddress.NodeAddress, 6);
} else {
CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
RtlCopyMemory (CurAddress->Address, &TempBuffer.IpxAddress, sizeof(TDI_ADDRESS_IPX));
}
++TransportAddress->TAAddressCount;
TransportAddressSize += ElementSize;
CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
}
Status = TdiCopyBufferToMdl (
TransportAddress,
0,
TransportAddressSize,
REQUEST_NDIS_BUFFER(Request),
0,
&ActualBytesCopied);
REQUEST_INFORMATION(Request) = ActualBytesCopied;
// CTEFreeMem (TransportAddress);
NbiFreeMemory( TransportAddress, TransportAddressAllocSize, MEMORY_QUERY, "Temp Query Allocation");
}
#endif _PNP_POWER
break;
}
default:
NB_DEBUG (QUERY, ("Invalid query type %d\n", Query->QueryType));
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
return Status;
} /* NbiTdiQueryInformation */
NTSTATUS
NbiStoreAdapterStatus(
IN ULONG MaximumLength,
IN USHORT NicId,
OUT PVOID * StatusBuffer,
OUT ULONG * StatusBufferLength,
OUT ULONG * ValidBufferLength
)
/*++
Routine Description:
This routine allocates an ADAPTER_STATUS buffer and
fills it in. The buffer will be allocated at most
MaximumLength size. The caller is responsible for
freeing the buffer.
Arguments:
MaximumLength - The maximum length to allocate.
NicId - The NIC ID the query was received on, or 0 for
a local query.
StatusBuffer - Returns the allocated buffer.
StatusBufferLength - Returns the length of the buffer.
ValidBufferLength - Returns the length of the buffer which
contains valid adapter status data.
Return Value:
STATUS_SUCCESS - The buffer was written successfully.
STATUS_BUFFER_OVERFLOW - The buffer was written but not all
data could fit in MaximumLength bytes.
STATUS_INSUFFICIENT_RESOURCES - The buffer could not be allocated.
--*/
{
PADAPTER_STATUS AdapterStatus;
PNAME_BUFFER NameBuffer;
ADAPTER_STATUS TempAdapterStatus;
#if !defined(_PNP_POWER)
TDI_ADDRESS_IPX IpxAddress;
#endif !_PNP_POWER
PDEVICE Device = NbiDevice;
PADDRESS Address;
UCHAR NameCount;
ULONG LengthNeeded;
ULONG BytesWritten;
NTSTATUS Status;
PLIST_ENTRY p;
CTELockHandle LockHandle;
//
// First fill in the basic adapter status structure, to make
// it easier to copy over if the target buffer is really short.
//
RtlZeroMemory ((PVOID)&TempAdapterStatus, sizeof(ADAPTER_STATUS));
#if defined(_PNP_POWER)
RtlCopyMemory (TempAdapterStatus.adapter_address, Device->Bind.Node, 6);
#else
(VOID)(*Device->Bind.QueryHandler)( // Check return code
IPX_QUERY_IPX_ADDRESS,
NicId,
&IpxAddress,
sizeof(TDI_ADDRESS_IPX),
NULL);
RtlCopyMemory (TempAdapterStatus.adapter_address, IpxAddress.NodeAddress, 6);
#endif _PNP_POWER
//
// Some of the fields mean different things for Novell Netbios,
// as described in the comments.
//
TempAdapterStatus.rev_major = 0; // Jumpers
TempAdapterStatus.reserved0 = 0; // SelfTest
TempAdapterStatus.adapter_type = 0; // MajorVersion
TempAdapterStatus.rev_minor = 0; // MinorVersion
TempAdapterStatus.duration = 0; // ReportingPeriod
TempAdapterStatus.frmr_recv = 0; // ReceiveCRCErrors
TempAdapterStatus.frmr_xmit = 0; // ReceiveAlignErrors
TempAdapterStatus.iframe_recv_err = 0; // XmitCollisions
TempAdapterStatus.xmit_aborts = 0; // XmitAbort
TempAdapterStatus.xmit_success = Device->Statistics.DataFramesSent; // SuccessfulXmits
TempAdapterStatus.recv_success = Device->Statistics.DataFramesReceived; // SuccessfulReceive
TempAdapterStatus.iframe_xmit_err = (WORD)Device->Statistics.DataFramesResent; // XmitRetries
TempAdapterStatus.recv_buff_unavail = (WORD)Device->Statistics.DataFramesRejected; // ExhaustedResource
// t1_timeouts, ti_timeouts, and reserved1 are unused.
TempAdapterStatus.free_ncbs = 0xffff; // FreeBlocks
TempAdapterStatus.max_cfg_ncbs = 0xffff; // ConfiguredNCB
TempAdapterStatus.max_ncbs = 0xffff; // MaxNCB
// xmit_bug_unavail and max_dgram_size are unused.
TempAdapterStatus.pending_sess = (WORD)Device->Statistics.OpenConnections; // CurrentSessions
TempAdapterStatus.max_cfg_sess = 0xffff; // MaxSessionConfigured
TempAdapterStatus.max_sess = 0xffff; // MaxSessionPossible
TempAdapterStatus.max_sess_pkt_size = (USHORT)
(Device->Bind.LineInfo.MaximumSendSize - sizeof(NB_CONNECTION)); // MaxSessionPacketSize
TempAdapterStatus.name_count = 0;
//
// Do a quick estimate of how many names we need room for.
// This includes stopping addresses and the broadcast
// address, for the moment.
//
NB_GET_LOCK (&Device->Lock, &LockHandle);
LengthNeeded = sizeof(ADAPTER_STATUS) + (Device->AddressCount * sizeof(NAME_BUFFER));
if (LengthNeeded > MaximumLength) {
LengthNeeded = MaximumLength;
}
AdapterStatus = NbiAllocateMemory(LengthNeeded, MEMORY_STATUS, "Adapter Status");
if (AdapterStatus == NULL) {
NB_FREE_LOCK (&Device->Lock, LockHandle);
return STATUS_INSUFFICIENT_RESOURCES;
}
*StatusBuffer = AdapterStatus;
*StatusBufferLength = LengthNeeded;
if (LengthNeeded < sizeof(ADAPTER_STATUS)) {
RtlCopyMemory (AdapterStatus, &TempAdapterStatus, LengthNeeded);
*ValidBufferLength = LengthNeeded;
NB_FREE_LOCK (&Device->Lock, LockHandle);
return STATUS_BUFFER_OVERFLOW;
}
RtlCopyMemory (AdapterStatus, &TempAdapterStatus, sizeof(ADAPTER_STATUS));
BytesWritten = sizeof(ADAPTER_STATUS);
NameBuffer = (PNAME_BUFFER)(AdapterStatus+1);
NameCount = 0;
//
// Scan through the device's address database, filling in
// the NAME_BUFFERs.
//
Status = STATUS_SUCCESS;
for (p = Device->AddressDatabase.Flink;
p != &Device->AddressDatabase;
p = p->Flink) {
Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
//
// Ignore addresses that are shutting down.
//
#if defined(_PNP_POWER)
if ((Address->State != ADDRESS_STATE_OPEN) ||
(Address->Flags & ADDRESS_FLAGS_CONFLICT)) {
continue;
}
#else
if ((Address->State != ADDRESS_STATE_OPEN) != 0) {
continue;
}
#endif _PNP_POWER
//
// Ignore the broadcast address.
//
if (Address->NetbiosAddress.Broadcast) {
continue;
}
//
// Ignore our reserved address.
//
#if defined(_PNP_POWER)
if ( NbiFindAdapterAddress(
Address->NetbiosAddress.NetbiosName,
LOCK_ACQUIRED
)) {
continue;
}
#else
if (RtlEqualMemory(
Address->NetbiosAddress.NetbiosName,
Device->ReservedNetbiosName,
16)) {
continue;
}
#endif _PNP_POWER
//
// Make sure we still have room.
//
if (BytesWritten + sizeof(NAME_BUFFER) > LengthNeeded) {
Status = STATUS_BUFFER_OVERFLOW;
break;
}
RtlCopyMemory(
NameBuffer->name,
Address->NetbiosAddress.NetbiosName,
16);
++NameCount;
NameBuffer->name_num = NameCount;
NameBuffer->name_flags = REGISTERED;
if (Address->NameTypeFlag == NB_NAME_GROUP) {
NameBuffer->name_flags |= GROUP_NAME;
}
BytesWritten += sizeof(NAME_BUFFER);
++NameBuffer;
}
AdapterStatus->name_count = (WORD)NameCount;
*ValidBufferLength = BytesWritten;
NB_FREE_LOCK (&Device->Lock, LockHandle);
return Status;
} /* NbiStoreAdapterStatus */
VOID
NbiUpdateNetbiosFindName(
IN PREQUEST Request,
#if defined(_PNP_POWER)
IN PNIC_HANDLE NicHandle,
#else
IN USHORT NicId,
#endif _PNP_POWER
IN TDI_ADDRESS_IPX UNALIGNED * RemoteIpxAddress,
IN BOOLEAN Unique
)
/*++
Routine Description:
This routine updates the find name request with the
new information received. It updates the status in
the request if needed.
Arguments:
Request - The netbios find name request.
NicId - The NIC ID the response was received on.
RemoteIpxAddress - The IPX address of the remote.
Unique - TRUE if the name is unique.
Return Value:
None.
--*/
{
FIND_NAME_HEADER UNALIGNED * FindNameHeader = NULL;
FIND_NAME_BUFFER UNALIGNED * FindNameBuffer;
UINT FindNameBufferLength;
TDI_ADDRESS_IPX LocalIpxAddress;
IPX_SOURCE_ROUTING_INFO SourceRoutingInfo;
NTSTATUS QueryStatus;
UINT i;
NdisQueryBufferSafe (REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength,
HighPagePriority);
if (!FindNameHeader)
{
return;
}
//
// Scan through the names saved so far and see if this one
// is there.
//
FindNameBuffer = (FIND_NAME_BUFFER UNALIGNED *)(FindNameHeader+1);
for (i = 0; i < FindNameHeader->node_count; i++) {
if (RtlEqualMemory(
FindNameBuffer->source_addr,
RemoteIpxAddress->NodeAddress,
6)) {
//
// This remote already responded, ignore it.
//
return;
}
FindNameBuffer = (FIND_NAME_BUFFER UNALIGNED *) (((PUCHAR)FindNameBuffer) + 33);
}
//
// Make sure there is room for this new node. 33 is
// sizeof(FIND_NAME_BUFFER) without padding.
//
if (FindNameBufferLength < sizeof(FIND_NAME_HEADER) + ((FindNameHeader->node_count+1) * 33)) {
REQUEST_STATUS(Request) = STATUS_BUFFER_OVERFLOW;
return;
}
//
// Query the local address, which we will return as
// the destination address of this query.
//
#if defined(_PNP_POWER)
if( (*NbiDevice->Bind.QueryHandler)( // Check return code
IPX_QUERY_IPX_ADDRESS,
NicHandle,
&LocalIpxAddress,
sizeof(TDI_ADDRESS_IPX),
NULL) != STATUS_SUCCESS ) {
//
// Ignore this response if the query fails. maybe the NicHandle
// is bad or it just got removed.
//
NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_IPX_ADDRESS,
NicHandle->NicId ));
return;
}
#else
(VOID)(*NbiDevice->Bind.QueryHandler)( // Check return code
IPX_QUERY_IPX_ADDRESS,
NicId,
&LocalIpxAddress,
sizeof(TDI_ADDRESS_IPX),
NULL);
#endif _PNP_POWER
FindNameBuffer->access_control = 0x10; // standard token-ring values
FindNameBuffer->frame_control = 0x40;
RtlMoveMemory (FindNameBuffer->destination_addr, LocalIpxAddress.NodeAddress, 6);
RtlCopyMemory (FindNameBuffer->source_addr, RemoteIpxAddress->NodeAddress, 6);
//
// Query source routing information about this remote, if any.
//
SourceRoutingInfo.Identifier = IDENTIFIER_NB;
RtlCopyMemory (SourceRoutingInfo.RemoteAddress, RemoteIpxAddress->NodeAddress, 6);
QueryStatus = (*NbiDevice->Bind.QueryHandler)(
IPX_QUERY_SOURCE_ROUTING,
#if defined(_PNP_POWER)
NicHandle,
#else
NicId,
#endif _PNP_POWER
&SourceRoutingInfo,
sizeof(IPX_SOURCE_ROUTING_INFO),
NULL);
RtlZeroMemory(FindNameBuffer->routing_info, 18);
if (QueryStatus != STATUS_SUCCESS) {
SourceRoutingInfo.SourceRoutingLength = 0;
} else if (SourceRoutingInfo.SourceRoutingLength > 0) {
RtlMoveMemory(
FindNameBuffer->routing_info,
SourceRoutingInfo.SourceRouting,
SourceRoutingInfo.SourceRoutingLength);
}
FindNameBuffer->length = (UCHAR)(14 + SourceRoutingInfo.SourceRoutingLength);
++FindNameHeader->node_count;
if (!Unique) {
FindNameHeader->unique_group = 1; // group
}
REQUEST_STATUS(Request) = STATUS_SUCCESS;
} /* NbiUpdateNetbiosFindName */
VOID
NbiSetNetbiosFindNameInformation(
IN PREQUEST Request
)
/*++
Routine Description:
This routine sets the REQUEST_INFORMATION field to the right
value based on the number of responses recorded in the netbios
find name request's buffer.
Arguments:
Request - The netbios find name request.
Return Value:
None.
--*/
{
FIND_NAME_HEADER UNALIGNED * FindNameHeader = NULL;
UINT FindNameBufferLength;
NdisQueryBufferSafe (REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength,
HighPagePriority);
if (FindNameHeader)
{
//
// 33 is sizeof(FIND_NAME_BUFFER) without the padding.
//
REQUEST_INFORMATION(Request) = sizeof(FIND_NAME_HEADER) + (FindNameHeader->node_count * 33);
}
} /* NbiSetNetbiosFindNameInformation */
NTSTATUS
NbiTdiSetInformation(
IN PDEVICE Device,
IN PREQUEST Request
)
/*++
Routine Description:
This routine performs the TdiSetInformation request for the transport
provider.
Arguments:
Device - the device.
Request - the request for the operation.
Return Value:
NTSTATUS - status of operation.
--*/
{
UNREFERENCED_PARAMETER (Device);
UNREFERENCED_PARAMETER (Request);
return STATUS_NOT_IMPLEMENTED;
} /* NbiTdiSetInformation */
VOID
NbiProcessStatusQuery(
IN PIPX_LOCAL_TARGET RemoteAddress,
IN ULONG MacOptions,
IN PUCHAR PacketBuffer,
IN UINT PacketSize
)
/*++
Routine Description:
This routine handles NB_CMD_STATUS_QUERY frames.
Arguments:
RemoteAddress - The local target this packet was received from.
MacOptions - The MAC options for the underlying NDIS binding.
LookaheadBuffer - The packet data, starting at the IPX
header.
PacketSize - The total length of the packet, starting at the
IPX header.
Return Value:
None.
--*/
{
PSINGLE_LIST_ENTRY s;
PNB_SEND_RESERVED Reserved;
PNDIS_PACKET Packet;
NB_CONNECTIONLESS UNALIGNED * Header;
NDIS_STATUS NdisStatus;
IPX_LINE_INFO LineInfo;
ULONG ResponseSize;
NTSTATUS Status;
PNDIS_BUFFER AdapterStatusBuffer;
PADAPTER_STATUS AdapterStatus;
ULONG AdapterStatusLength;
ULONG ValidStatusLength;
PDEVICE Device = NbiDevice;
NB_CONNECTIONLESS UNALIGNED * Connectionless =
(NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
//
// The old stack does not include the 14 bytes of padding in
// the 802.3 or IPX length of the packet.
//
if (PacketSize < (sizeof(IPX_HEADER) + 2)) {
return;
}
//
// Get the maximum size we can send.
//
#if defined(_PNP_POWER)
if( (*Device->Bind.QueryHandler)( // Check return code
IPX_QUERY_LINE_INFO,
&RemoteAddress->NicHandle,
&LineInfo,
sizeof(IPX_LINE_INFO),
NULL) != STATUS_SUCCESS ) {
//
// Bad NicHandle or it just got removed.
//
NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_LINE_INFO,
RemoteAddress->NicHandle.NicId ));
return;
}
//
// Allocate a packet from the pool.
//
s = NbiPopSendPacket(Device, FALSE);
if (s == NULL) {
return;
}
#else
//
// Allocate a packet from the pool.
//
s = NbiPopSendPacket(Device, FALSE);
if (s == NULL) {
return;
}
//
// Get the maximum size we can send.
//
(VOID)(*Device->Bind.QueryHandler)( // Check return code
IPX_QUERY_LINE_INFO,
RemoteAddress->NicId,
&LineInfo,
sizeof(IPX_LINE_INFO),
NULL);
#endif _PNP_POWER
ResponseSize = LineInfo.MaximumSendSize - sizeof(IPX_HEADER) - sizeof(NB_STATUS_RESPONSE);
//
// Get the local adapter status (this allocates a buffer).
//
Status = NbiStoreAdapterStatus(
ResponseSize,
#if defined(_PNP_POWER)
RemoteAddress->NicHandle.NicId,
#else
RemoteAddress->NicId,
#endif _PNP_POWER
&AdapterStatus,
&AdapterStatusLength,
&ValidStatusLength);
if (Status == STATUS_INSUFFICIENT_RESOURCES) {
ExInterlockedPushEntrySList(
&Device->SendPacketList,
s,
&NbiGlobalPoolInterlock);
return;
}
//
// Allocate an NDIS buffer to map the extra buffer.
//
NdisAllocateBuffer(
&NdisStatus,
&AdapterStatusBuffer,
Device->NdisBufferPoolHandle,
AdapterStatus,
ValidStatusLength);
if (NdisStatus != NDIS_STATUS_SUCCESS) {
NbiFreeMemory (AdapterStatus, AdapterStatusLength, MEMORY_STATUS, "Adapter Status");
ExInterlockedPushEntrySList(
&Device->SendPacketList,
s,
&NbiGlobalPoolInterlock);
return;
}
NB_DEBUG2 (QUERY, ("Reply to AdapterStatus from %lx %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
*(UNALIGNED ULONG *)Connectionless->IpxHeader.SourceNetwork,
Connectionless->IpxHeader.SourceNode[0],
Connectionless->IpxHeader.SourceNode[1],
Connectionless->IpxHeader.SourceNode[2],
Connectionless->IpxHeader.SourceNode[3],
Connectionless->IpxHeader.SourceNode[4],
Connectionless->IpxHeader.SourceNode[5]));
Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
CTEAssert (Reserved->SendInProgress == FALSE);
Reserved->SendInProgress = TRUE;
Reserved->Type = SEND_TYPE_STATUS_RESPONSE;
Reserved->u.SR_AS.ActualBufferLength = AdapterStatusLength;
//
// Fill in the IPX header -- the default header has the broadcast
// address on net 0 as the destination IPX address.
//
Header = (NB_CONNECTIONLESS UNALIGNED *)
(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, Connectionless->IpxHeader.SourceNetwork, 12);
Header->IpxHeader.PacketLength[0] = (UCHAR)((sizeof(IPX_HEADER)+sizeof(NB_STATUS_RESPONSE)+ValidStatusLength) / 256);
Header->IpxHeader.PacketLength[1] = (UCHAR)((sizeof(IPX_HEADER)+sizeof(NB_STATUS_RESPONSE)+ValidStatusLength) % 256);
Header->IpxHeader.PacketType = 0x04;
//
// Now fill in the Netbios header.
//
Header->StatusResponse.ConnectionControlFlag = 0x00;
Header->StatusResponse.DataStreamType = NB_CMD_STATUS_RESPONSE;
NbiReferenceDevice (Device, DREF_STATUS_RESPONSE);
NdisChainBufferAtBack (Packet, AdapterStatusBuffer);
//
// Now send the frame, IPX will adjust the length of the
// first buffer correctly.
//
NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE));
if ((NdisStatus =
(*Device->Bind.SendHandler)(
RemoteAddress,
Packet,
sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + ValidStatusLength,
sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE))) != STATUS_PENDING) {
NbiSendComplete(
Packet,
NdisStatus);
}
} /* NbiProcessStatusQuery */
VOID
NbiSendStatusQuery(
IN PREQUEST Request
)
/*++
Routine Description:
This routine sends NB_CMD_STATUS_QUERY frames.
Arguments:
Request - Holds the request describing the remote adapter
status query. REQUEST_STATUS(Request) points
to the netbios cache entry for the remote name.
Return Value:
None.
--*/
{
PSINGLE_LIST_ENTRY s;
PNB_SEND_RESERVED Reserved;
PNDIS_PACKET Packet;
NB_CONNECTIONLESS UNALIGNED * Header;
NDIS_STATUS NdisStatus;
PNETBIOS_CACHE CacheName;
PIPX_LOCAL_TARGET LocalTarget;
PDEVICE Device = NbiDevice;
//
// Allocate a packet from the pool.
//
s = NbiPopSendPacket(Device, FALSE);
if (s == NULL) {
return;
}
Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
CTEAssert (Reserved->SendInProgress == FALSE);
Reserved->SendInProgress = TRUE;
Reserved->Type = SEND_TYPE_STATUS_QUERY;
CacheName = (PNETBIOS_CACHE)REQUEST_STATUSPTR(Request);
//
// Fill in the IPX header -- the default header has the broadcast
// address on net 0 as the destination IPX address.
//
Header = (NB_CONNECTIONLESS UNALIGNED *)
(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
RtlCopyMemory (Header->IpxHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
LocalTarget = &CacheName->Networks[0].LocalTarget;
Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_QUERY)) / 256;
Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_QUERY)) % 256;
Header->IpxHeader.PacketType = 0x04;
//
// Now fill in the Netbios header.
//
Header->StatusResponse.ConnectionControlFlag = 0x00;
Header->StatusResponse.DataStreamType = NB_CMD_STATUS_QUERY;
NbiReferenceDevice (Device, DREF_STATUS_FRAME);
//
// Now send the frame, IPX will adjust the length of the
// first buffer correctly.
//
NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY));
if ((NdisStatus =
(*Device->Bind.SendHandler)(
LocalTarget,
Packet,
sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY),
sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY))) != STATUS_PENDING) {
NbiSendComplete(
Packet,
NdisStatus);
}
} /* NbiProcessStatusQuery */
VOID
NbiProcessStatusResponse(
IN NDIS_HANDLE MacBindingHandle,
IN NDIS_HANDLE MacReceiveContext,
IN PIPX_LOCAL_TARGET RemoteAddress,
IN ULONG MacOptions,
IN PUCHAR LookaheadBuffer,
IN UINT LookaheadBufferSize,
IN UINT LookaheadBufferOffset,
IN UINT PacketSize
)
/*++
Routine Description:
This routine handles NB_CMD_STATUS_RESPONSE frames.
Arguments:
MacBindingHandle - A handle to use when calling NdisTransferData.
MacReceiveContext - A context to use when calling NdisTransferData.
RemoteAddress - The local target this packet was received from.
MacOptions - The MAC options for the underlying NDIS binding.
LookaheadBuffer - The lookahead buffer, starting at the IPX
header.
LookaheadBufferSize - The length of the lookahead data.
LookaheadBufferOffset - The offset to add when calling
NdisTransferData.
PacketSize - The total length of the packet, starting at the
IPX header.
Return Value:
None.
--*/
{
PDEVICE Device = NbiDevice;
CTELockHandle LockHandle;
PREQUEST AdapterStatusRequest;
PNETBIOS_CACHE CacheName;
PLIST_ENTRY p;
PSINGLE_LIST_ENTRY s;
PNDIS_BUFFER TargetBuffer;
ULONG TargetBufferLength, BytesToTransfer;
ULONG BytesTransferred;
NDIS_STATUS NdisStatus;
PNB_RECEIVE_RESERVED ReceiveReserved;
PNDIS_PACKET Packet;
BOOLEAN Found;
PNAME_BUFFER NameBuffer;
UINT i,NameCount = 0;
NB_CONNECTIONLESS UNALIGNED * Connectionless =
(NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer;
if (PacketSize < (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE))) {
return;
}
//
// Find out how many names are there.
//
NameBuffer = (PNAME_BUFFER)(LookaheadBuffer + sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS));
if ( LookaheadBufferSize > sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS) ) {
NameCount = (LookaheadBufferSize - (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS)) ) /
sizeof(NAME_BUFFER);
}
//
// Find a request queued to this remote. If there are
// multiple requests outstanding for the same name we
// should get multiple responses, so we only need to
// find one.
//
NB_GET_LOCK (&Device->Lock, &LockHandle);
Found = FALSE;
p = Device->ActiveAdapterStatus.Flink;
while (p != &Device->ActiveAdapterStatus) {
AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
p = p->Flink;
CacheName = (PNETBIOS_CACHE)REQUEST_STATUSPTR(AdapterStatusRequest);
if ( CacheName->Unique ) {
if (RtlEqualMemory(
&CacheName->FirstResponse,
Connectionless->IpxHeader.SourceNetwork,
12)) {
Found = TRUE;
break;
}
} else if ( RtlEqualMemory( CacheName->NetbiosName,NetbiosBroadcastName,16)){
//
// It's a broadcast name. Any response is fine.
//
Found = TRUE;
break;
} else {
//
// It's group name. Make sure that this remote
// has this group name registered with him.
//
for (i =0;i<NameCount;i++) {
if ( (RtlEqualMemory(
CacheName->NetbiosName,
NameBuffer[i].name,
16)) &&
(NameBuffer[i].name_flags & GROUP_NAME) ) {
Found = TRUE;
break;
}
}
}
}
if (!Found) {
NB_FREE_LOCK (&Device->Lock, LockHandle);
return;
}
NB_DEBUG2 (QUERY, ("Got response to AdapterStatus %lx\n", AdapterStatusRequest));
RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
if (--CacheName->ReferenceCount == 0) {
NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
NbiFreeMemory(
CacheName,
sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
MEMORY_CACHE,
"Name deleted");
}
NB_FREE_LOCK (&Device->Lock, LockHandle);
s = NbiPopReceivePacket (Device);
if (s == NULL) {
REQUEST_INFORMATION (AdapterStatusRequest) = 0;
REQUEST_STATUS (AdapterStatusRequest) = STATUS_INSUFFICIENT_RESOURCES;
NbiCompleteRequest (AdapterStatusRequest);
NbiFreeRequest (Device, AdapterStatusRequest);
NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
return;
}
ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
//
// Initialize the receive packet.
//
ReceiveReserved->Type = RECEIVE_TYPE_ADAPTER_STATUS;
ReceiveReserved->u.RR_AS.Request = AdapterStatusRequest;
REQUEST_STATUS(AdapterStatusRequest) = STATUS_SUCCESS;
CTEAssert (!ReceiveReserved->TransferInProgress);
ReceiveReserved->TransferInProgress = TRUE;
//
// Now that we have a packet and a buffer, set up the transfer.
// We will complete the request when the transfer completes.
//
TargetBuffer = REQUEST_NDIS_BUFFER (AdapterStatusRequest);
NdisChainBufferAtFront (Packet, TargetBuffer);
NbiGetBufferChainLength (TargetBuffer, &TargetBufferLength);
BytesToTransfer = PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE));
if (TargetBufferLength < BytesToTransfer) {
BytesToTransfer = TargetBufferLength;
REQUEST_STATUS(AdapterStatusRequest) = STATUS_BUFFER_OVERFLOW;
}
(*Device->Bind.TransferDataHandler) (
&NdisStatus,
MacBindingHandle,
MacReceiveContext,
LookaheadBufferOffset + (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE)),
BytesToTransfer,
Packet,
&BytesTransferred);
if (NdisStatus != NDIS_STATUS_PENDING) {
#if DBG
if (NdisStatus == STATUS_SUCCESS) {
CTEAssert (BytesTransferred == BytesToTransfer);
}
#endif
NbiTransferDataComplete(
Packet,
NdisStatus,
BytesTransferred);
}
} /* NbiProcessStatusResponse */