windows-nt/Source/XPSP1/NT/net/atm/rawwan/sys/info.c
2020-09-26 16:20:57 +08:00

691 lines
14 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
D:\nt\private\ntos\tdi\rawwan\core\info.c
Abstract:
Routines for handling query/set information requests.
Revision History:
Who When What
-------- -------- ----------------------------------------------
arvindm 06-09-97 Created
Notes:
--*/
#include <precomp.h>
#define _FILENUMBER 'OFNI'
//
// Kludgy way to ensure we have enough space for a transport
// address in the following INFO BUF structure.
//
#define MAX_RWAN_TDI_INFO_LENGTH 200
typedef union _RWAN_TDI_INFO_BUF
{
TDI_CONNECTION_INFO ConnInfo;
TDI_ADDRESS_INFO AddrInfo;
TDI_PROVIDER_INFO ProviderInfo;
TDI_PROVIDER_STATISTICS ProviderStats;
UCHAR Space[MAX_RWAN_TDI_INFO_LENGTH];
} RWAN_TDI_INFO_BUF, *PRWAN_TDI_INFO_BUF;
TDI_STATUS
RWanTdiQueryInformation(
IN PTDI_REQUEST pTdiRequest,
IN UINT QueryType,
IN PNDIS_BUFFER pNdisBuffer,
IN PUINT pBufferSize,
IN UINT IsConnection
)
/*++
Routine Description:
This is the TDI entry point to handle a QueryInformation TDI request.
Arguments:
pTdiRequest - Pointer to the TDI Request
QueryType - Information being queried for
pNdisBuffer - Start of list of buffers containing query data
pBufferSize - Total space in above list
IsConnection - Is this query on a connection endpoint?
Return Value:
TDI_STATUS: TDI_SUCCESS if the query was processed
successfully, TDI_STATUS_XXX for any error.
--*/
{
TDI_STATUS TdiStatus;
RWAN_TDI_INFO_BUF InfoBuf;
PVOID InfoPtr;
UINT InfoSize;
UINT Offset;
UINT Size;
UINT BytesCopied;
PRWAN_TDI_PROTOCOL pProtocol;
PRWAN_TDI_ADDRESS pAddrObject;
PRWAN_TDI_CONNECTION pConnObject;
RWAN_CONN_ID ConnId;
TdiStatus = TDI_SUCCESS;
InfoPtr = NULL;
switch (QueryType)
{
case TDI_QUERY_BROADCAST_ADDRESS:
TdiStatus = TDI_INVALID_QUERY;
break;
case TDI_QUERY_PROVIDER_INFO:
pProtocol = pTdiRequest->Handle.ControlChannel;
RWAN_STRUCT_ASSERT(pProtocol, ntp);
InfoBuf.ProviderInfo = pProtocol->ProviderInfo;
InfoSize = sizeof(TDI_PROVIDER_INFO);
InfoPtr = &InfoBuf.ProviderInfo;
break;
case TDI_QUERY_ADDRESS_INFO:
if (IsConnection)
{
ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
RWAN_ACQUIRE_CONN_TABLE_LOCK();
pConnObject = RWanGetConnFromId(ConnId);
RWAN_RELEASE_CONN_TABLE_LOCK();
if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
{
TdiStatus = TDI_INVALID_CONNECTION;
break;
}
pAddrObject = pConnObject->pAddrObject;
}
else
{
pAddrObject = (PRWAN_TDI_ADDRESS)pTdiRequest->Handle.AddressHandle;
}
if (pAddrObject == NULL_PRWAN_TDI_ADDRESS)
{
TdiStatus = TDI_INVALID_CONNECTION;
break;
}
RWAN_STRUCT_ASSERT(pAddrObject, nta);
RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
RWAN_ASSERT(pAddrObject->AddressLength <=
(sizeof(RWAN_TDI_INFO_BUF) - sizeof(TDI_ADDRESS_INFO)));
InfoSize = sizeof(TDI_ADDRESS_INFO) - sizeof(TRANSPORT_ADDRESS) +
pAddrObject->AddressLength;
InfoBuf.AddrInfo.ActivityCount = 1; // same as TCP
InfoBuf.AddrInfo.Address.TAAddressCount = 1;
InfoBuf.AddrInfo.Address.Address[0].AddressLength = pAddrObject->AddressLength;
InfoBuf.AddrInfo.Address.Address[0].AddressType = pAddrObject->AddressType;
RWAN_COPY_MEM(InfoBuf.AddrInfo.Address.Address[0].Address,
pAddrObject->pAddress,
pAddrObject->AddressLength);
RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
RWANDEBUGP(DL_LOUD, DC_DISPATCH,
("RWanTdiQueryInfo: IsConn %d, Addr dump:\n", IsConnection));
RWANDEBUGPDUMP(DL_LOUD, DC_DISPATCH, pAddrObject->pAddress, pAddrObject->AddressLength);
InfoPtr = &InfoBuf.AddrInfo;
TdiStatus = TDI_SUCCESS;
break;
case TDI_QUERY_CONNECTION_INFO:
TdiStatus = TDI_INVALID_QUERY;
break;
case TDI_QUERY_PROVIDER_STATISTICS:
pProtocol = pTdiRequest->Handle.ControlChannel;
RWAN_STRUCT_ASSERT(pProtocol, ntp);
InfoBuf.ProviderStats = pProtocol->ProviderStats;
InfoSize = sizeof(TDI_PROVIDER_STATISTICS);
InfoPtr = &InfoBuf.ProviderStats;
break;
default:
TdiStatus = TDI_INVALID_QUERY;
break;
}
if (TdiStatus == TDI_SUCCESS)
{
RWAN_ASSERT(InfoPtr != NULL);
Offset = 0;
Size = *pBufferSize;
(VOID)RWanCopyFlatToNdis(
pNdisBuffer,
InfoPtr,
MIN(InfoSize, Size),
&Offset,
&BytesCopied
);
if (Size < InfoSize)
{
TdiStatus = TDI_BUFFER_OVERFLOW;
}
else
{
*pBufferSize = InfoSize;
}
}
return (TdiStatus);
}
RWAN_STATUS
RWanHandleGenericConnQryInfo(
IN HANDLE ConnectionContext,
IN PVOID pInputBuffer,
IN ULONG InputBufferLength,
OUT PVOID pOutputBuffer,
IN OUT PVOID pOutputBufferLength
)
/*++
Routine Description:
Handle a generic QueryInformation command on a Connection Object.
Arguments:
AddrHandle - Pointer to our address object structure
ConnectionContext - TDI Connection ID
pInputBuffer - Query Info structure
InputBufferLength - Length of the above
pOutputBuffer - Output buffer
pOutputBufferLength - Space available/bytes filled in.
Return Value:
RWAN_STATUS_SUCCESS if the command was processed successfully,
RWAN_STATUS_XXX if not.
--*/
{
PRWAN_TDI_CONNECTION pConnObject;
RWAN_STATUS RWanStatus;
PRWAN_QUERY_INFORMATION_EX pQueryInfo;
RWanStatus = RWAN_STATUS_SUCCESS;
do
{
if (InputBufferLength < sizeof(RWAN_QUERY_INFORMATION_EX) ||
pOutputBuffer == NULL)
{
RWanStatus = RWAN_STATUS_RESOURCES;
break;
}
RWAN_ACQUIRE_CONN_TABLE_LOCK();
pConnObject = RWanGetConnFromId((RWAN_CONN_ID)PtrToUlong(ConnectionContext));
RWAN_RELEASE_CONN_TABLE_LOCK();
if (pConnObject == NULL)
{
RWanStatus = RWAN_STATUS_BAD_PARAMETER;
break;
}
RWAN_STRUCT_ASSERT(pConnObject, ntc);
pQueryInfo = (PRWAN_QUERY_INFORMATION_EX)pInputBuffer;
if (InputBufferLength < sizeof(RWAN_QUERY_INFORMATION_EX) + pQueryInfo->ContextLength - sizeof(UCHAR))
{
RWanStatus = RWAN_STATUS_RESOURCES;
break;
}
switch (pQueryInfo->ObjectId)
{
case RWAN_OID_CONN_OBJECT_MAX_MSG_SIZE:
if (*(PULONG)(ULONG_PTR)pOutputBufferLength < sizeof(ULONG))
{
RWanStatus = RWAN_STATUS_RESOURCES;
break;
}
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
if (pConnObject->NdisConnection.pNdisVc)
{
*(PULONG)(ULONG_PTR)pOutputBuffer = pConnObject->NdisConnection.pNdisVc->MaxSendSize;
*(PULONG)(ULONG_PTR)pOutputBufferLength = sizeof(ULONG);
}
else
{
RWanStatus = RWAN_STATUS_BAD_PARAMETER;
}
RWAN_RELEASE_CONN_LOCK(pConnObject);
break;
default:
RWanStatus = RWAN_STATUS_BAD_PARAMETER;
break;
}
break;
}
while (FALSE);
RWANDEBUGP(DL_LOUD, DC_BIND,
("RWanHandleGenericConnQry: returning status %x\n", RWanStatus));
return (RWanStatus);
}
RWAN_STATUS
RWanHandleGenericAddrSetInfo(
IN HANDLE AddrHandle,
IN PVOID pInputBuffer,
IN ULONG InputBufferLength
)
/*++
Routine Description:
Handle a non-media specific SetInformation command on an Address Object.
Arguments:
AddrHandle - Pointer to our address object structure
pInputBuffer - Set Info structure
InputBufferLength - Length of the above
Return Value:
RWAN_STATUS_SUCCESS if the command was processed successfully,
RWAN_STATUS_XXX if not.
--*/
{
PRWAN_TDI_ADDRESS pAddrObject;
PRWAN_TDI_CONNECTION pConnObject;
PRWAN_SET_INFORMATION_EX pSetInfo;
RWAN_STATUS RWanStatus;
ULONG Flags;
RWanStatus = RWAN_STATUS_SUCCESS;
pAddrObject = (PRWAN_TDI_ADDRESS)AddrHandle;
do
{
if (pAddrObject == NULL)
{
RWanStatus = RWAN_STATUS_BAD_ADDRESS;
break;
}
RWAN_STRUCT_ASSERT(pAddrObject, nta);
if (InputBufferLength < sizeof(RWAN_SET_INFORMATION_EX))
{
RWanStatus = RWAN_STATUS_RESOURCES;
break;
}
pSetInfo = (PRWAN_SET_INFORMATION_EX)pInputBuffer;
if (InputBufferLength < sizeof(RWAN_SET_INFORMATION_EX) + pSetInfo->BufferSize - sizeof(UCHAR))
{
RWanStatus = RWAN_STATUS_RESOURCES;
break;
}
switch (pSetInfo->ObjectId)
{
case RWAN_OID_ADDRESS_OBJECT_FLAGS:
if (pSetInfo->BufferSize < sizeof(ULONG))
{
RWanStatus = RWAN_STATUS_RESOURCES;
break;
}
Flags = *((PULONG)&pSetInfo->Buffer[0]);
if (Flags & RWAN_AOFLAG_C_ROOT)
{
//
// This Address Object is designated as the Root of
// an outgoing Point to Multipoint connection.
//
RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
RWAN_SET_BIT(pAddrObject->Flags, RWANF_AO_PMP_ROOT);
if (pAddrObject->pRootConnObject != NULL)
{
RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
RWanStatus = RWAN_STATUS_BAD_ADDRESS;
break;
}
//
// There should be a single Connection Object associated
// with this Address Object. That should now be designated
// the Root Connection Object.
//
RWAN_ASSERT(!RWAN_IS_LIST_EMPTY(&pAddrObject->IdleConnList));
pConnObject = CONTAINING_RECORD(pAddrObject->IdleConnList.Flink, RWAN_TDI_CONNECTION, ConnLink);
RWAN_STRUCT_ASSERT(pConnObject, ntc);
pAddrObject->pRootConnObject = pConnObject;
RWAN_ACQUIRE_CONN_LOCK_DPC(pConnObject);
RWAN_SET_BIT(pConnObject->Flags, RWANF_CO_ROOT);
RWAN_RELEASE_CONN_LOCK_DPC(pConnObject);
RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
RWANDEBUGP(DL_LOUD, DC_ADDRESS,
("Marked PMP Root: AddrObj x%x, ConnObj x%x\n",
pAddrObject, pConnObject));
}
break;
default:
RWanStatus = RWAN_STATUS_BAD_PARAMETER;
break;
}
break;
}
while (FALSE);
RWANDEBUGP(DL_VERY_LOUD, DC_DISPATCH,
("Generic Set Addr: AddrObj x%x, returning x%x\n", pAddrObject, RWanStatus));
return (RWanStatus);
}
RWAN_STATUS
RWanHandleMediaSpecificAddrSetInfo(
IN HANDLE AddrHandle,
IN PVOID pInputBuffer,
IN ULONG InputBufferLength
)
/*++
Routine Description:
Handle a media specific SetInformation command on an Address Object.
Arguments:
AddrHandle - Pointer to our address object structure
pInputBuffer - Set Info structure
InputBufferLength - Length of the above
Return Value:
RWAN_STATUS_SUCCESS if the command was processed successfully,
RWAN_STATUS_XXX if not.
--*/
{
PRWAN_NDIS_AF_CHARS pAfChars;
PRWAN_TDI_ADDRESS pAddrObject;
RWAN_STATUS RWanStatus;
ULONG Flags;
RWanStatus = RWAN_STATUS_SUCCESS;
pAddrObject = (PRWAN_TDI_ADDRESS)AddrHandle;
do
{
if (pAddrObject == NULL)
{
RWanStatus = RWAN_STATUS_BAD_ADDRESS;
break;
}
RWAN_STRUCT_ASSERT(pAddrObject, nta);
pAfChars = &(pAddrObject->pProtocol->pAfInfo->AfChars);
if (pAfChars->pAfSpSetAddrInformation != NULL)
{
RWanStatus = (*pAfChars->pAfSpSetAddrInformation)(
pAddrObject->AfSpAddrContext,
pInputBuffer,
InputBufferLength
);
}
else
{
RWanStatus = RWAN_STATUS_FAILURE;
}
break;
}
while (FALSE);
return (RWanStatus);
}
RWAN_STATUS
RWanHandleMediaSpecificConnQryInfo(
IN HANDLE ConnectionContext,
IN PVOID pInputBuffer,
IN ULONG InputBufferLength,
OUT PVOID pOutputBuffer,
IN OUT PVOID pOutputBufferLength
)
/*++
Routine Description:
Handle a media specific QueryInformation command on a Connection Object.
Arguments:
AddrHandle - Pointer to our address object structure
ConnectionContext - TDI Connection ID
pInputBuffer - Query Info structure
InputBufferLength - Length of the above
pOutputBuffer - Output buffer
pOutputBufferLength - Space available/bytes filled in.
Return Value:
RWAN_STATUS_SUCCESS if the command was processed successfully,
RWAN_STATUS_XXX if not.
--*/
{
PRWAN_NDIS_AF_CHARS pAfChars;
PRWAN_TDI_CONNECTION pConnObject;
RWAN_STATUS RWanStatus;
ULONG Flags;
RWanStatus = RWAN_STATUS_SUCCESS;
do
{
RWAN_ACQUIRE_CONN_TABLE_LOCK();
pConnObject = RWanGetConnFromId((RWAN_CONN_ID)PtrToUlong(ConnectionContext));
RWAN_RELEASE_CONN_TABLE_LOCK();
if ((pConnObject == NULL) ||
(pConnObject->pAddrObject == NULL))
{
RWanStatus = RWAN_STATUS_BAD_PARAMETER;
break;
}
RWAN_STRUCT_ASSERT(pConnObject, ntc);
pAfChars = &(pConnObject->pAddrObject->pProtocol->pAfInfo->AfChars);
if (pAfChars->pAfSpQueryConnInformation != NULL)
{
RWanStatus = (*pAfChars->pAfSpQueryConnInformation)(
pConnObject->AfSpConnContext,
pInputBuffer,
InputBufferLength,
pOutputBuffer,
pOutputBufferLength
);
}
else
{
RWanStatus = RWAN_STATUS_FAILURE;
}
break;
}
while (FALSE);
return (RWanStatus);
}
PNDIS_BUFFER
RWanCopyFlatToNdis(
IN PNDIS_BUFFER pDestBuffer,
IN PUCHAR pSrcBuffer,
IN UINT LengthToCopy,
IN OUT PUINT pStartOffset,
OUT PUINT pBytesCopied
)
/*++
Routine Description:
Copy from a flat memory buffer to an NDIS buffer chain. It is assumed
that the NDIS buffer chain has enough space.
TBD: Use the TDI function for copying from flat mem to MDL.
Arguments:
pDestBuffer - First buffer in the destination NDIS buffer chain.
pSrcBuffer - Pointer to start of flat memory
LengthToCopy - Max bytes to copy
pStartOffset - Copy offset in first buffer
pBytesCopied - Place to return actual bytes copied
Return Value:
Pointer to buffer in chain where data can be copied into next.
Also, *pStartOffset and *pBytesCopied are set.
--*/
{
UINT CopyLength;
PUCHAR pDest;
UINT Offset;
UINT BytesCopied;
UINT DestSize;
UINT CopySize;
BytesCopied = 0;
Offset = *pStartOffset;
pDest = (PUCHAR)NdisBufferVirtualAddress(pDestBuffer) + Offset;
DestSize = NdisBufferLength(pDestBuffer) - Offset;
for (;;)
{
CopySize = MIN(DestSize, LengthToCopy);
RWAN_COPY_MEM(pDest, pSrcBuffer, CopySize);
pDest += CopySize;
pSrcBuffer += CopySize;
BytesCopied += CopySize;
LengthToCopy -= CopySize;
if (LengthToCopy == 0)
{
break;
}
DestSize -= CopySize;
if (DestSize == 0)
{
pDestBuffer = NDIS_BUFFER_LINKAGE(pDestBuffer);
RWAN_ASSERT(pDestBuffer != NULL);
pDest = NdisBufferVirtualAddress(pDestBuffer);
DestSize = NdisBufferLength(pDestBuffer);
}
}
//
// Prepare return values.
//
*pStartOffset = (UINT)(pDest - (PUCHAR)NdisBufferVirtualAddress(pDestBuffer));
*pBytesCopied = BytesCopied;
return (pDestBuffer);
}