mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
690 lines
14 KiB
690 lines
14 KiB
/*++
|
|
|
|
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);
|
|
}
|
|
|
|
|