1839 lines
52 KiB
C
1839 lines
52 KiB
C
/*++
|
||
|
||
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 */
|
||
|