1400 lines
57 KiB
C
1400 lines
57 KiB
C
/***************************************************************************
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
UTIL.C
|
|
|
|
Abstract:
|
|
|
|
Utility routines for Remote NDIS Miniport driver
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
|
PURPOSE.
|
|
|
|
Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
|
|
|
|
|
|
Revision History:
|
|
|
|
5/17/99 : created
|
|
|
|
Author:
|
|
|
|
Tom Green
|
|
|
|
|
|
****************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
ULONG MsgFrameAllocs = 0;
|
|
|
|
/****************************************************************************/
|
|
/* MemAlloc */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Allocate memory */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Buffer - pointer to buffer pointer */
|
|
/* Length - length of buffer to allocate */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* NDIS_STATUS */
|
|
/* */
|
|
/****************************************************************************/
|
|
NDIS_STATUS
|
|
MemAlloc(OUT PVOID *Buffer, IN UINT Length)
|
|
{
|
|
NDIS_STATUS Status;
|
|
|
|
TRACE3(("MemAlloc\n"));
|
|
ASSERT(Length != 0);
|
|
|
|
Status = NdisAllocateMemoryWithTag(Buffer,
|
|
Length,
|
|
RNDISMP_TAG_GEN_ALLOC);
|
|
|
|
// zero out allocation
|
|
if(Status == NDIS_STATUS_SUCCESS)
|
|
NdisZeroMemory(*Buffer, Length);
|
|
|
|
return Status;
|
|
} // MemAlloc
|
|
|
|
/****************************************************************************/
|
|
/* MemFree */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Free memory */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Buffer - pointer to buffer */
|
|
/* Length - length of buffer to allocate */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
MemFree(IN PVOID Buffer, IN UINT Length)
|
|
{
|
|
TRACE3(("MemFree\n"));
|
|
|
|
NdisFreeMemory(Buffer, Length, 0);
|
|
} // MemFree
|
|
|
|
|
|
/****************************************************************************/
|
|
/* AddAdapter */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Add an adapter to the list of adapters associated with this driver */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pAdapter - Adapter object, contains pointer to associated driver block */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
AddAdapter(IN PRNDISMP_ADAPTER pAdapter)
|
|
{
|
|
PDRIVER_BLOCK DriverBlock = pAdapter->DriverBlock;
|
|
|
|
TRACE3(("AddpAdapter\n"));
|
|
|
|
CHECK_VALID_ADAPTER(pAdapter);
|
|
|
|
// grab the global spinlock
|
|
NdisAcquireSpinLock(&RndismpGlobalLock);
|
|
|
|
pAdapter->NextAdapter = DriverBlock->AdapterList;
|
|
DriverBlock->AdapterList = pAdapter;
|
|
|
|
// keep track of number of adapters associated with this driver block
|
|
DriverBlock->NumberAdapters++;
|
|
|
|
// release global spinlock
|
|
NdisReleaseSpinLock(&RndismpGlobalLock);
|
|
|
|
} // AddAdapter
|
|
|
|
|
|
/****************************************************************************/
|
|
/* RemoveAdapter */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Remove an adapter from the list of adapters associated with this driver */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pAdapter - Adapter object, contains pointer to associated driver block */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
RemoveAdapter(IN PRNDISMP_ADAPTER pAdapter)
|
|
{
|
|
PDRIVER_BLOCK DriverBlock = pAdapter->DriverBlock;
|
|
|
|
TRACE3(("RemoveAdapter\n"));
|
|
|
|
CHECK_VALID_ADAPTER(pAdapter);
|
|
|
|
// remove the adapter from the driver block list of adapters.
|
|
|
|
// grab the global spinlock
|
|
NdisAcquireSpinLock(&RndismpGlobalLock);
|
|
|
|
// see if it is the first one
|
|
if (DriverBlock->AdapterList == pAdapter)
|
|
{
|
|
DriverBlock->AdapterList = pAdapter->NextAdapter;
|
|
|
|
}
|
|
// not the first one, so walk the list
|
|
else
|
|
{
|
|
PRNDISMP_ADAPTER * ppAdapter = &DriverBlock->AdapterList;
|
|
|
|
while (*ppAdapter != pAdapter)
|
|
{
|
|
ASSERT(*ppAdapter != NULL);
|
|
ppAdapter = &((*ppAdapter)->NextAdapter);
|
|
}
|
|
|
|
*ppAdapter = pAdapter->NextAdapter;
|
|
}
|
|
|
|
// removing this adapter
|
|
DriverBlock->NumberAdapters--;
|
|
|
|
// release global spinlock
|
|
NdisReleaseSpinLock(&RndismpGlobalLock);
|
|
|
|
} // RemoveAdapter
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DeviceObjectToAdapter */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Given a pointer to an FDO, return the corresponding Adapter structure, */
|
|
/* if it exists, and the driver block. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pDeviceObject - pointer to the device object to search for. */
|
|
/* ppAdapter - place to return pointer to the adapter structure. */
|
|
/* ppDriverBlock - place to return pointer to driver block. */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
DeviceObjectToAdapterAndDriverBlock(IN PDEVICE_OBJECT pDeviceObject,
|
|
OUT PRNDISMP_ADAPTER * ppAdapter,
|
|
OUT PDRIVER_BLOCK * ppDriverBlock)
|
|
{
|
|
PDRIVER_BLOCK pDriverBlock;
|
|
PRNDISMP_ADAPTER pAdapter;
|
|
|
|
pAdapter = NULL;
|
|
pDriverBlock = DeviceObjectToDriverBlock(&RndismpMiniportBlockListHead, pDeviceObject);
|
|
if (pDriverBlock != NULL)
|
|
{
|
|
NdisAcquireSpinLock(&RndismpGlobalLock);
|
|
|
|
for (pAdapter = pDriverBlock->AdapterList;
|
|
pAdapter != NULL;
|
|
pAdapter = pAdapter->NextAdapter)
|
|
{
|
|
if (pAdapter->pDeviceObject == pDeviceObject)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
NdisReleaseSpinLock(&RndismpGlobalLock);
|
|
}
|
|
|
|
*ppAdapter = pAdapter;
|
|
*ppDriverBlock = pDriverBlock;
|
|
|
|
} // DeviceObjectToAdapter
|
|
|
|
/****************************************************************************/
|
|
/* AddDriverBlock */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Add driver block to list of drivers (microports) associated with this */
|
|
/* driver */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Head - head of list */
|
|
/* Item - driver block to add to list */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
AddDriverBlock(IN PDRIVER_BLOCK Head, IN PDRIVER_BLOCK Item)
|
|
{
|
|
TRACE3(("AddDriverBlock\n"));
|
|
|
|
CHECK_VALID_BLOCK(Item);
|
|
|
|
// first time through, so allocate global spinlock
|
|
if(!RndismpNumMicroports)
|
|
NdisAllocateSpinLock(&RndismpGlobalLock);
|
|
|
|
// grab the global spinlock
|
|
NdisAcquireSpinLock(&RndismpGlobalLock);
|
|
|
|
// Link the driver block on the global list of driver blocks
|
|
Item->NextDriverBlock = Head->NextDriverBlock;
|
|
Head->NextDriverBlock = Item;
|
|
|
|
// keep track of how many microports we support so we can free
|
|
// global resources
|
|
RndismpNumMicroports++;
|
|
|
|
// release global spinlock
|
|
NdisReleaseSpinLock(&RndismpGlobalLock);
|
|
|
|
} // AddDriverBlock
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
/* RemoveDriverBlock */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Remove driver block from list of drivers (microports) associated with */
|
|
/* this driver */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Head - head of list */
|
|
/* Item - driver block to remove from list */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
RemoveDriverBlock(IN PDRIVER_BLOCK BlockHead, IN PDRIVER_BLOCK Item)
|
|
{
|
|
UINT NumMicroports;
|
|
|
|
PDRIVER_BLOCK Head = BlockHead;
|
|
|
|
TRACE1(("RemoveDriverBlock\n"));
|
|
|
|
CHECK_VALID_BLOCK(Item);
|
|
|
|
// grab the global spinlock
|
|
NdisAcquireSpinLock(&RndismpGlobalLock);
|
|
|
|
// Remove the driver block from the global list of driver blocks
|
|
while(Head->NextDriverBlock != Item)
|
|
{
|
|
Head = Head->NextDriverBlock;
|
|
|
|
// make sure this is valid
|
|
if(!Head)
|
|
break;
|
|
}
|
|
|
|
if(Head)
|
|
Head->NextDriverBlock = Head->NextDriverBlock->NextDriverBlock;
|
|
|
|
// keep track of how many microports we support so we can free
|
|
// global resources
|
|
RndismpNumMicroports--;
|
|
|
|
NumMicroports = RndismpNumMicroports;
|
|
|
|
// release global spinlock
|
|
NdisReleaseSpinLock(&RndismpGlobalLock);
|
|
|
|
// see if we need to free global spinlock
|
|
if(!RndismpNumMicroports)
|
|
NdisFreeSpinLock(&RndismpGlobalLock);
|
|
|
|
ASSERT(Head);
|
|
|
|
} // RemoveDriverBlock
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DeviceObjectToDriverBlock */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Get driver block pointer associated with the PDO passed in */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Head - head of driver block list */
|
|
/* DeviceObject - device object we want to get associated driver block for */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* PDRIVER_BLOCK */
|
|
/* */
|
|
/****************************************************************************/
|
|
PDRIVER_BLOCK
|
|
DeviceObjectToDriverBlock(IN PDRIVER_BLOCK Head,
|
|
IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
PDRIVER_OBJECT DriverObject;
|
|
|
|
TRACE3(("DeviceObjectToDriverBlock\n"));
|
|
|
|
// grab the global spinlock
|
|
NdisAcquireSpinLock(&RndismpGlobalLock);
|
|
|
|
// get the driver object for this adapter
|
|
DriverObject = DeviceObjectToDriverObject(DeviceObject);
|
|
|
|
Head = Head->NextDriverBlock;
|
|
|
|
// walk the list of driver blocks to find a match with driver object
|
|
while(Head->DriverObject != DriverObject)
|
|
{
|
|
Head = Head->NextDriverBlock;
|
|
|
|
// break out if we are at the end of the list
|
|
if(!Head)
|
|
break;
|
|
}
|
|
|
|
// release global spinlock
|
|
NdisReleaseSpinLock(&RndismpGlobalLock);
|
|
|
|
CHECK_VALID_BLOCK(Head);
|
|
|
|
return Head;
|
|
|
|
} // DeviceObjectToDriverBlock
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DriverObjectToDriverBlock */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Get driver block pointer associated with the Driver Object passed in */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Head - head of driver block list */
|
|
/* DriverObject - Driver object we want to get associated driver block for */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* PDRIVER_BLOCK */
|
|
/* */
|
|
/****************************************************************************/
|
|
PDRIVER_BLOCK
|
|
DriverObjectToDriverBlock(IN PDRIVER_BLOCK Head,
|
|
IN PDRIVER_OBJECT DriverObject)
|
|
{
|
|
TRACE3(("DriverObjectToDriverBlock\n"));
|
|
|
|
// grab the global spinlock
|
|
NdisAcquireSpinLock(&RndismpGlobalLock);
|
|
|
|
Head = Head->NextDriverBlock;
|
|
|
|
// walk the list of driver blocks to find a match with driver object
|
|
while(Head->DriverObject != DriverObject)
|
|
{
|
|
Head = Head->NextDriverBlock;
|
|
|
|
// break out if we are at the end of the list
|
|
if(!Head)
|
|
break;
|
|
}
|
|
|
|
// release global spinlock
|
|
NdisReleaseSpinLock(&RndismpGlobalLock);
|
|
|
|
CHECK_VALID_BLOCK(Head);
|
|
|
|
return Head;
|
|
|
|
} // DriverObjectToDriverBlock
|
|
|
|
|
|
/****************************************************************************/
|
|
/* AllocateMsgFrame */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Allocate a frame that holds context about a message we are about to */
|
|
/* send. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pAdapter - Adapter object */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* PRNDISMP_MESSAGE_FRAME */
|
|
/* */
|
|
/****************************************************************************/
|
|
PRNDISMP_MESSAGE_FRAME
|
|
AllocateMsgFrame(IN PRNDISMP_ADAPTER pAdapter)
|
|
{
|
|
PRNDISMP_MESSAGE_FRAME pMsgFrame;
|
|
|
|
#ifndef DONT_USE_LOOKASIDE_LIST
|
|
pMsgFrame = (PRNDISMP_MESSAGE_FRAME)
|
|
NdisAllocateFromNPagedLookasideList(&pAdapter->MsgFramePool);
|
|
|
|
#else
|
|
{
|
|
NDIS_STATUS Status;
|
|
Status = MemAlloc(&pMsgFrame, sizeof(RNDISMP_MESSAGE_FRAME));
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
pMsgFrame = NULL;
|
|
}
|
|
}
|
|
#endif // DONT_USE_LOOKASIDE_LIST
|
|
|
|
if (pMsgFrame)
|
|
{
|
|
NdisZeroMemory(pMsgFrame, sizeof(*pMsgFrame));
|
|
pMsgFrame->pAdapter = pAdapter;
|
|
pMsgFrame->RequestId = NdisInterlockedIncrement(&pAdapter->RequestId);
|
|
pMsgFrame->Signature = FRAME_SIGNATURE;
|
|
|
|
pMsgFrame->RefCount = 1;
|
|
NdisInterlockedIncrement(&MsgFrameAllocs);
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
TRACE1(("AllocateMsgFrame: pAdapter %x, MsgFramePool at %x, alloc failed, count %d\n",
|
|
pAdapter, &pAdapter->MsgFramePool, MsgFrameAllocs));
|
|
DbgBreakPoint();
|
|
}
|
|
#endif // DBG
|
|
|
|
return (pMsgFrame);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* DereferenceMsgFrame */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Free a message frame and any associated resources. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Frame - pointer to frame */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
DereferenceMsgFrame(IN PRNDISMP_MESSAGE_FRAME pMsgFrame)
|
|
{
|
|
PRNDISMP_ADAPTER pAdapter;
|
|
PMDL pMdl;
|
|
PUCHAR pMessage;
|
|
|
|
CHECK_VALID_FRAME(pMsgFrame);
|
|
|
|
if (NdisInterlockedDecrement(&pMsgFrame->RefCount) == 0)
|
|
{
|
|
//
|
|
// Mess up the contents slightly to catch bugs resulting from
|
|
// improper reuse of this frame after it is freed.
|
|
//
|
|
pMsgFrame->Signature++;
|
|
|
|
pMdl = pMsgFrame->pMessageMdl;
|
|
pMsgFrame->pMessageMdl = NULL;
|
|
|
|
if (pMdl)
|
|
{
|
|
pMessage = MmGetMdlVirtualAddress(pMdl);
|
|
}
|
|
else
|
|
{
|
|
pMessage = NULL;
|
|
}
|
|
|
|
if (pMessage)
|
|
{
|
|
MemFree(pMessage, -1);
|
|
IoFreeMdl(pMdl);
|
|
}
|
|
|
|
pAdapter = pMsgFrame->pAdapter;
|
|
|
|
#ifndef DONT_USE_LOOKASIDE_LIST
|
|
NdisFreeToNPagedLookasideList(&pAdapter->MsgFramePool, pMsgFrame);
|
|
#else
|
|
MemFree(pMsgFrame, sizeof(RNDISMP_MESSAGE_FRAME));
|
|
#endif
|
|
NdisInterlockedDecrement(&MsgFrameAllocs);
|
|
}
|
|
|
|
} // DereferenceMsgFrame
|
|
|
|
|
|
/****************************************************************************/
|
|
/* ReferenceMsgFrame */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Add a ref count to a message frame */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Frame - pointer to frame */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
ReferenceMsgFrame(IN PRNDISMP_MESSAGE_FRAME pMsgFrame)
|
|
{
|
|
NdisInterlockedIncrement(&pMsgFrame->RefCount);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* KeepAliveTimerHandler */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Timer that keeps tabs on messages coming up from the device and */
|
|
/* sends a "KeepAlive" message if the device has been inactive too long */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* SystemSpecific1 - Don't care */
|
|
/* Context - pAdapter object */
|
|
/* SystemSpecific2 - Don't care */
|
|
/* SystemSpecific3 - Don't care */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* PNDIS_PACKET */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
KeepAliveTimerHandler(IN PVOID SystemSpecific1,
|
|
IN PVOID Context,
|
|
IN PVOID SystemSpecific2,
|
|
IN PVOID SystemSpecific3)
|
|
{
|
|
PRNDISMP_ADAPTER pAdapter;
|
|
PRNDISMP_MESSAGE_FRAME pMsgFrame;
|
|
ULONG CurrentTime;
|
|
|
|
// get adapter context
|
|
pAdapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(Context);
|
|
|
|
TRACE2(("KeepAliveTimerHandler\n"));
|
|
|
|
do
|
|
{
|
|
// get current tick (in milliseconds)
|
|
NdisGetSystemUpTime(&CurrentTime);
|
|
|
|
// check and see if too much time has elapsed since we
|
|
// got the last message from the device
|
|
|
|
RNDISMP_ACQUIRE_ADAPTER_LOCK(pAdapter);
|
|
|
|
if (((CurrentTime - pAdapter->LastMessageFromDevice) > KEEP_ALIVE_TIMER))
|
|
{
|
|
// see if we have a keep alive message pending, so let's bong this
|
|
if (pAdapter->KeepAliveMessagePending)
|
|
{
|
|
TRACE1(("KeepAliveTimer: Adapter %x, message pending\n", pAdapter));
|
|
|
|
// indicate later from check for hang handler
|
|
pAdapter->NeedReset = TRUE;
|
|
|
|
RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
|
|
|
|
RNDISMP_INCR_STAT(pAdapter, KeepAliveTimeout);
|
|
|
|
break;
|
|
}
|
|
|
|
RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
|
|
|
|
|
|
// too much time has elapsed, send down a keep alive message
|
|
pMsgFrame = BuildRndisMessageCommon(pAdapter,
|
|
NULL,
|
|
REMOTE_NDIS_KEEPALIVE_MSG,
|
|
0,
|
|
NULL,
|
|
0);
|
|
|
|
if (pMsgFrame)
|
|
{
|
|
RNDISMP_ACQUIRE_ADAPTER_LOCK(pAdapter);
|
|
|
|
pAdapter->KeepAliveMessagePending = TRUE;
|
|
pAdapter->KeepAliveMessagePendingId = pMsgFrame->RequestId;
|
|
|
|
RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
|
|
|
|
// send the message to the microport
|
|
RNDISMP_SEND_TO_MICROPORT(pAdapter, pMsgFrame, FALSE, CompleteSendKeepAlive);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
|
|
}
|
|
}
|
|
while (FALSE);
|
|
|
|
// see if the timer was cancelled somewhere
|
|
if (!pAdapter->TimerCancelled)
|
|
{
|
|
// restart timer
|
|
NdisSetTimer(&pAdapter->KeepAliveTimer, KEEP_ALIVE_TIMER / 2);
|
|
}
|
|
} // KeepAliveTimerHandler
|
|
|
|
|
|
/****************************************************************************/
|
|
/* CompleteSendKeepAlive */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Callback routine to handle completion of send by the microport, for */
|
|
/* a keepalive message. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pMsgFrame - Pointer to message frame describing the message */
|
|
/* SendStatus - Status returned by microport */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
CompleteSendKeepAlive(IN PRNDISMP_MESSAGE_FRAME pMsgFrame,
|
|
IN NDIS_STATUS SendStatus)
|
|
{
|
|
PRNDISMP_ADAPTER pAdapter;
|
|
|
|
pAdapter = pMsgFrame->pAdapter;
|
|
|
|
DereferenceMsgFrame(pMsgFrame);
|
|
|
|
if (SendStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
TRACE1(("KeepAlive send failure %x on Adapter %x\n",
|
|
SendStatus, pAdapter));
|
|
|
|
RNDISMP_ACQUIRE_ADAPTER_LOCK(pAdapter);
|
|
|
|
pAdapter->KeepAliveMessagePending = FALSE;
|
|
pAdapter->NeedReset = FALSE;
|
|
|
|
RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
|
|
}
|
|
|
|
} // CompleteSendKeepAlive
|
|
|
|
|
|
/****************************************************************************/
|
|
/* BuildRndisMessageCommon */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Allocate resources for meesage and frame and build RNDIS message */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pAdapter - adapter object */
|
|
/* pVc - optionally, VC on which this message is sent. */
|
|
/* NdisMessageType - RNDIS message type */
|
|
/* Oid - the NDIS_OID to process. */
|
|
/* InformationBuffer - Holds the data to be set. */
|
|
/* InformationBufferLength - The length of InformationBuffer. */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* PRNDISMP_MESSAGE_FRAME */
|
|
/* */
|
|
/****************************************************************************/
|
|
PRNDISMP_MESSAGE_FRAME
|
|
BuildRndisMessageCommon(IN PRNDISMP_ADAPTER pAdapter,
|
|
IN PRNDISMP_VC pVc OPTIONAL,
|
|
IN UINT NdisMessageType,
|
|
IN NDIS_OID Oid,
|
|
IN PVOID InformationBuffer,
|
|
IN ULONG InformationBufferLength)
|
|
{
|
|
PRNDIS_MESSAGE pMessage;
|
|
UINT MessageSize;
|
|
PRNDISMP_MESSAGE_FRAME pMsgFrame;
|
|
|
|
TRACE2(("BuildRndisMessageCommon\n"));
|
|
|
|
pMsgFrame = NULL;
|
|
|
|
switch(NdisMessageType)
|
|
{
|
|
case REMOTE_NDIS_INITIALIZE_MSG:
|
|
{
|
|
PRNDIS_INITIALIZE_REQUEST pInitRequest;
|
|
|
|
MessageSize = RNDIS_MESSAGE_SIZE(RNDIS_INITIALIZE_REQUEST);
|
|
|
|
// get a message and request frame
|
|
pMsgFrame = AllocateMessageAndFrame(pAdapter,
|
|
MessageSize);
|
|
|
|
if (pMsgFrame == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame);
|
|
pMessage->NdisMessageType = NdisMessageType;
|
|
pMsgFrame->NdisMessageType = NdisMessageType;
|
|
TRACE1(("RNDISMP: Init Req message %x, Type %d, Length %d, MaxRcv %d\n",
|
|
pMessage, pMessage->NdisMessageType, pMessage->MessageLength, pAdapter->MaxReceiveSize));
|
|
|
|
pInitRequest = &pMessage->Message.InitializeRequest;
|
|
pInitRequest->RequestId = pMsgFrame->RequestId;
|
|
pInitRequest->MajorVersion = RNDIS_MAJOR_VERSION;
|
|
pInitRequest->MinorVersion = RNDIS_MINOR_VERSION;
|
|
pInitRequest->MaxTransferSize = pAdapter->MaxReceiveSize;
|
|
|
|
break;
|
|
}
|
|
case REMOTE_NDIS_HALT_MSG:
|
|
{
|
|
PRNDIS_HALT_REQUEST pHaltRequest;
|
|
|
|
MessageSize = RNDIS_MESSAGE_SIZE(RNDIS_HALT_REQUEST);
|
|
|
|
// get a message and request frame
|
|
pMsgFrame = AllocateMessageAndFrame(pAdapter,
|
|
MessageSize);
|
|
|
|
if (pMsgFrame == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame);
|
|
pMessage->NdisMessageType = NdisMessageType;
|
|
pMsgFrame->NdisMessageType = NdisMessageType;
|
|
pHaltRequest = &pMessage->Message.HaltRequest;
|
|
pHaltRequest->RequestId = pMsgFrame->RequestId;
|
|
|
|
break;
|
|
}
|
|
case REMOTE_NDIS_QUERY_MSG:
|
|
{
|
|
PRNDIS_QUERY_REQUEST pQueryRequest;
|
|
|
|
MessageSize = RNDIS_MESSAGE_SIZE(RNDIS_QUERY_REQUEST) + InformationBufferLength;
|
|
|
|
// get a message and request frame
|
|
pMsgFrame = AllocateMessageAndFrame(pAdapter,
|
|
MessageSize);
|
|
|
|
if (pMsgFrame == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame);
|
|
pMessage->NdisMessageType = NdisMessageType;
|
|
pMsgFrame->NdisMessageType = NdisMessageType;
|
|
|
|
pQueryRequest = &pMessage->Message.QueryRequest;
|
|
pQueryRequest->RequestId = pMsgFrame->RequestId;
|
|
pQueryRequest->Oid = Oid;
|
|
pQueryRequest->InformationBufferLength = InformationBufferLength;
|
|
pQueryRequest->InformationBufferOffset = sizeof(RNDIS_QUERY_REQUEST);
|
|
|
|
if (pVc == NULL)
|
|
{
|
|
pQueryRequest->DeviceVcHandle = NULL_DEVICE_CONTEXT;
|
|
}
|
|
else
|
|
{
|
|
pQueryRequest->DeviceVcHandle = pVc->DeviceVcContext;
|
|
}
|
|
|
|
TRACE2(("Query OID %x, Len %d, RequestId %08X\n",
|
|
Oid, InformationBufferLength, pQueryRequest->RequestId));
|
|
|
|
// copy information buffer
|
|
RNDISMP_MOVE_MEM(RNDISMP_GET_INFO_BUFFER_FROM_QUERY_MSG(pQueryRequest),
|
|
InformationBuffer,
|
|
InformationBufferLength);
|
|
break;
|
|
}
|
|
case REMOTE_NDIS_SET_MSG:
|
|
{
|
|
PRNDIS_SET_REQUEST pSetRequest;
|
|
|
|
MessageSize = RNDIS_MESSAGE_SIZE(RNDIS_SET_REQUEST) + InformationBufferLength;
|
|
|
|
// get a message and request frame
|
|
pMsgFrame = AllocateMessageAndFrame(pAdapter,
|
|
MessageSize);
|
|
|
|
if (pMsgFrame == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame);
|
|
pMessage->NdisMessageType = NdisMessageType;
|
|
pMsgFrame->NdisMessageType = NdisMessageType;
|
|
|
|
pSetRequest = &pMessage->Message.SetRequest;
|
|
pSetRequest->RequestId = pMsgFrame->RequestId;
|
|
pSetRequest->Oid = Oid;
|
|
pSetRequest->InformationBufferLength = InformationBufferLength;
|
|
pSetRequest->InformationBufferOffset = sizeof(RNDIS_SET_REQUEST);
|
|
|
|
if (pVc == NULL)
|
|
{
|
|
pSetRequest->DeviceVcHandle = NULL_DEVICE_CONTEXT;
|
|
}
|
|
else
|
|
{
|
|
pSetRequest->DeviceVcHandle = pVc->DeviceVcContext;
|
|
}
|
|
|
|
// copy information buffer
|
|
RNDISMP_MOVE_MEM(RNDISMP_GET_INFO_BUFFER_FROM_QUERY_MSG(pSetRequest),
|
|
InformationBuffer,
|
|
InformationBufferLength);
|
|
break;
|
|
}
|
|
case REMOTE_NDIS_RESET_MSG:
|
|
{
|
|
PRNDIS_RESET_REQUEST pResetRequest;
|
|
|
|
MessageSize = RNDIS_MESSAGE_SIZE(RNDIS_RESET_REQUEST);
|
|
|
|
// get a message and request frame
|
|
pMsgFrame = AllocateMessageAndFrame(pAdapter,
|
|
MessageSize);
|
|
|
|
if (pMsgFrame == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame);
|
|
pMessage->NdisMessageType = NdisMessageType;
|
|
pMsgFrame->NdisMessageType = NdisMessageType;
|
|
|
|
pResetRequest = &pMessage->Message.ResetRequest;
|
|
pResetRequest->Reserved = 0;
|
|
break;
|
|
}
|
|
case REMOTE_NDIS_KEEPALIVE_MSG:
|
|
{
|
|
PRNDIS_KEEPALIVE_REQUEST pKeepAliveRequest;
|
|
|
|
MessageSize = RNDIS_MESSAGE_SIZE(RNDIS_KEEPALIVE_REQUEST);
|
|
|
|
// get a message and request frame
|
|
pMsgFrame = AllocateMessageAndFrame(pAdapter,
|
|
MessageSize);
|
|
|
|
if (pMsgFrame == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame);
|
|
pMessage->NdisMessageType = NdisMessageType;
|
|
pMsgFrame->NdisMessageType = NdisMessageType;
|
|
|
|
pKeepAliveRequest = &pMessage->Message.KeepaliveRequest;
|
|
pKeepAliveRequest->RequestId = pMsgFrame->RequestId;
|
|
break;
|
|
}
|
|
case REMOTE_NDIS_KEEPALIVE_CMPLT:
|
|
{
|
|
PRNDIS_KEEPALIVE_COMPLETE pKeepAliveComplete;
|
|
|
|
MessageSize = RNDIS_MESSAGE_SIZE(RNDIS_KEEPALIVE_COMPLETE);
|
|
|
|
// get a message and request frame
|
|
pMsgFrame = AllocateMessageAndFrame(pAdapter,
|
|
MessageSize);
|
|
|
|
if (pMsgFrame == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame);
|
|
pMessage->NdisMessageType = NdisMessageType;
|
|
pMsgFrame->NdisMessageType = NdisMessageType;
|
|
|
|
pKeepAliveComplete = &pMessage->Message.KeepaliveComplete;
|
|
pKeepAliveComplete->RequestId = *(RNDIS_REQUEST_ID *)InformationBuffer;
|
|
pKeepAliveComplete->Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TRACE2(("Invalid NdisMessageType (%08X)\n", NdisMessageType));
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
return pMsgFrame;
|
|
} // BuildRndisMessageCommon
|
|
|
|
|
|
/****************************************************************************/
|
|
/* AllocateMessageAndFrame */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Allocate a message and frame for an RNDIS message */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pAdapter - pAdapter object */
|
|
/* MessageSize - size of RNDIS message */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* PRNDISMP_MESSAGE_FRAME */
|
|
/* */
|
|
/****************************************************************************/
|
|
PRNDISMP_MESSAGE_FRAME
|
|
AllocateMessageAndFrame(IN PRNDISMP_ADAPTER pAdapter,
|
|
IN UINT MessageSize)
|
|
{
|
|
PRNDIS_MESSAGE pMessage = NULL;
|
|
PRNDISMP_MESSAGE_FRAME pMsgFrame = NULL;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PMDL pMdl = NULL;
|
|
|
|
TRACE3(("AllocateMessageAndFrame\n"));
|
|
|
|
do
|
|
{
|
|
// allocate a buffer for RNDIS message
|
|
Status = MemAlloc(&pMessage, MessageSize);
|
|
|
|
// see if we got our buffer
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// allocate an MDL to describe this message.
|
|
pMdl = IoAllocateMdl(
|
|
pMessage,
|
|
MessageSize,
|
|
FALSE,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (pMdl == NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
MmBuildMdlForNonPagedPool(pMdl);
|
|
|
|
// got the message buffer, now allocate a frame
|
|
pMsgFrame = AllocateMsgFrame(pAdapter);
|
|
|
|
if (pMsgFrame == NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
// got everything, so fill in some frame things
|
|
pMsgFrame->pMessageMdl = pMdl;
|
|
|
|
pMessage->MessageLength = MessageSize;
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (pMdl)
|
|
{
|
|
IoFreeMdl(pMdl);
|
|
}
|
|
|
|
if (pMessage)
|
|
{
|
|
MemFree(pMessage, MessageSize);
|
|
}
|
|
}
|
|
|
|
return pMsgFrame;
|
|
|
|
} // AllocateMessageAndFrame
|
|
|
|
|
|
/****************************************************************************/
|
|
/* FreeAdapter */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Free all memory allocations to do with an Adapter structure */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pAdapter - pointer to the adapter to be freed. */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/****************************************************************************/
|
|
VOID
|
|
FreeAdapter(IN PRNDISMP_ADAPTER Adapter)
|
|
{
|
|
// free up transport resources
|
|
FreeTransportResources(Adapter);
|
|
|
|
if (Adapter->DriverOIDList)
|
|
{
|
|
MemFree(Adapter->DriverOIDList, RndismpSupportedOidsNum*sizeof(NDIS_OID));
|
|
}
|
|
|
|
if (Adapter->FriendlyNameAnsi.Buffer)
|
|
{
|
|
MemFree(Adapter->FriendlyNameAnsi.Buffer, Adapter->FriendlyNameAnsi.MaximumLength);
|
|
}
|
|
|
|
if (Adapter->FriendlyNameUnicode.Buffer)
|
|
{
|
|
MemFree(Adapter->FriendlyNameUnicode.Buffer, Adapter->FriendlyNameUnicode.MaximumLength);
|
|
}
|
|
|
|
#if DBG
|
|
if (Adapter->pSendLogBuffer)
|
|
{
|
|
MemFree(Adapter->pSendLogBuffer, Adapter->LogBufferSize);
|
|
Adapter->pSendLogBuffer = NULL;
|
|
}
|
|
#endif // DBG
|
|
|
|
MemFree(Adapter, sizeof(RNDISMP_ADAPTER));
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* AllocateVc */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Allocate a VC structure */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pAdapter - adapter object */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* PRNDISMP_VC */
|
|
/* */
|
|
/****************************************************************************/
|
|
PRNDISMP_VC
|
|
AllocateVc(IN PRNDISMP_ADAPTER pAdapter)
|
|
{
|
|
PRNDISMP_VC pVc;
|
|
NDIS_STATUS Status;
|
|
|
|
Status = MemAlloc(&pVc, sizeof(RNDISMP_VC));
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pVc->pAdapter = pAdapter;
|
|
pVc->VcState = RNDISMP_VC_ALLOCATED;
|
|
pVc->CallState = RNDISMP_CALL_IDLE;
|
|
pVc->RefCount = 0;
|
|
RNDISMP_INIT_LOCK(&pVc->Lock);
|
|
|
|
EnterVcIntoHashTable(pAdapter, pVc);
|
|
}
|
|
else
|
|
{
|
|
pVc = NULL;
|
|
}
|
|
|
|
return pVc;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* DeallocateVc */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Deallocate a VC structure. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pVc - Pointer to VC being deallocated. */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
DeallocateVc(IN PRNDISMP_VC pVc)
|
|
{
|
|
ASSERT(pVc->RefCount == 0);
|
|
ASSERT(pVc->VcState == RNDISMP_VC_ALLOCATED);
|
|
|
|
RemoveVcFromHashTable(pVc->pAdapter, pVc);
|
|
|
|
MemFree(pVc, sizeof(RNDISMP_VC));
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* LookupVcId */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Search for a VC structure that matches a given VC Id. */
|
|
/* If we find the VC, we reference it and return it. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* Adapter - adapter object */
|
|
/* VcId - Id to search for */
|
|
/* */
|
|
/* Notes: */
|
|
/* */
|
|
/* This routine is called with the adapter lock held! */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* PRNDISMP_VC - pointer to VC, if one exists */
|
|
/* */
|
|
/****************************************************************************/
|
|
PRNDISMP_VC
|
|
LookupVcId(IN PRNDISMP_ADAPTER pAdapter,
|
|
IN UINT32 VcId)
|
|
{
|
|
PLIST_ENTRY pVcEnt;
|
|
PRNDISMP_VC pVc;
|
|
ULONG VcIdHash;
|
|
PRNDISMP_VC_HASH_TABLE pVcHashTable;
|
|
BOOLEAN bFound = FALSE;
|
|
|
|
VcIdHash = RNDISMP_HASH_VCID(VcId);
|
|
|
|
pVcHashTable = pAdapter->pVcHashTable;
|
|
|
|
do
|
|
{
|
|
if (pVcHashTable == NULL)
|
|
{
|
|
pVc = NULL;
|
|
break;
|
|
}
|
|
|
|
for (pVcEnt = pVcHashTable->HashEntry[VcIdHash].Flink;
|
|
pVcEnt != &pVcHashTable->HashEntry[VcIdHash];
|
|
pVcEnt = pVcEnt->Flink)
|
|
{
|
|
pVc = CONTAINING_RECORD(pVcEnt, RNDISMP_VC, VcList);
|
|
if (pVc->VcId == VcId)
|
|
{
|
|
bFound = TRUE;
|
|
|
|
RNDISMP_REF_VC(pVc);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
pVc = NULL;
|
|
}
|
|
}
|
|
while (FALSE);
|
|
|
|
return pVc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* EnterVcIntoHashTable */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Link a VC into the hash table after assigning it a VC Id. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pAdapter - adapter object */
|
|
/* pVc - VC to link to the above adapter */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
EnterVcIntoHashTable(IN PRNDISMP_ADAPTER pAdapter,
|
|
IN PRNDISMP_VC pVc)
|
|
{
|
|
PRNDISMP_VC pExistingVc;
|
|
PRNDISMP_VC_HASH_TABLE pVcHashTable;
|
|
UINT32 VcId;
|
|
ULONG VcIdHash;
|
|
|
|
RNDISMP_ACQUIRE_ADAPTER_LOCK(pAdapter);
|
|
|
|
//
|
|
// We pick the next sequentially higher Vc Id value for this VC,
|
|
// but check to see if it is already in use...
|
|
//
|
|
do
|
|
{
|
|
pAdapter->LastVcId++;
|
|
|
|
// Never allocate the value 0.
|
|
if (pAdapter->LastVcId == 0)
|
|
{
|
|
pAdapter->LastVcId++;
|
|
}
|
|
|
|
VcId = pAdapter->LastVcId;
|
|
|
|
pExistingVc = LookupVcId(pAdapter, VcId);
|
|
}
|
|
while (pExistingVc != NULL);
|
|
|
|
pVcHashTable = pAdapter->pVcHashTable;
|
|
pVc->VcId = VcId;
|
|
VcIdHash = RNDISMP_HASH_VCID(VcId);
|
|
|
|
InsertTailList(&pVcHashTable->HashEntry[VcIdHash], &pVc->VcList);
|
|
pVcHashTable->NumEntries++;
|
|
|
|
RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* RemoveVcFromHashTable */
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Routine Description: */
|
|
/* */
|
|
/* Unlink a VC from the adapter hash table. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* */
|
|
/* pAdapter - adapter object */
|
|
/* pVc - VC to be unlinked. */
|
|
/* */
|
|
/* Return: */
|
|
/* */
|
|
/* VOID */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID
|
|
RemoveVcFromHashTable(IN PRNDISMP_ADAPTER pAdapter,
|
|
IN PRNDISMP_VC pVc)
|
|
{
|
|
RNDISMP_ACQUIRE_ADAPTER_LOCK(pAdapter);
|
|
|
|
RemoveEntryList(&pVc->VcList);
|
|
|
|
pAdapter->pVcHashTable->NumEntries--;
|
|
|
|
RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
|
|
}
|
|
|
|
|