Leaked source code of windows server 2003
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.
 
 
 
 
 
 

5909 lines
153 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
miniport.c
Abstract:
ATM Ethernet PVC driver
Author:
ADube - created
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//--------------------------------------------------------------------------------
// //
// Global Variables used by miniports //
// //
//--------------------------------------------------------------------------------
static
NDIS_OID EthernetSupportedOids[] = {
OID_GEN_SUPPORTED_LIST,
OID_GEN_HARDWARE_STATUS,
OID_GEN_MEDIA_CONNECT_STATUS,
OID_GEN_MEDIA_SUPPORTED,
OID_GEN_MEDIA_IN_USE,
OID_GEN_MAXIMUM_LOOKAHEAD,
OID_GEN_MAXIMUM_FRAME_SIZE,
OID_GEN_MAXIMUM_TOTAL_SIZE,
OID_GEN_MAC_OPTIONS,
OID_GEN_PROTOCOL_OPTIONS,
OID_GEN_LINK_SPEED,
OID_GEN_TRANSMIT_BUFFER_SPACE,
OID_GEN_RECEIVE_BUFFER_SPACE,
OID_GEN_TRANSMIT_BLOCK_SIZE,
OID_GEN_RECEIVE_BLOCK_SIZE,
OID_GEN_MAXIMUM_SEND_PACKETS,
OID_GEN_VENDOR_DESCRIPTION,
OID_GEN_VENDOR_ID,
OID_GEN_DRIVER_VERSION,
OID_GEN_VENDOR_DRIVER_VERSION,
OID_GEN_CURRENT_PACKET_FILTER,
OID_GEN_CURRENT_LOOKAHEAD,
OID_GEN_XMIT_OK,
OID_GEN_RCV_OK,
OID_GEN_XMIT_ERROR,
OID_GEN_RCV_ERROR,
OID_GEN_RCV_NO_BUFFER,
OID_802_3_PERMANENT_ADDRESS,
OID_802_3_CURRENT_ADDRESS,
OID_802_3_MULTICAST_LIST,
OID_802_3_MAXIMUM_LIST_SIZE,
OID_802_3_RCV_ERROR_ALIGNMENT,
OID_802_3_XMIT_ONE_COLLISION,
OID_802_3_XMIT_MORE_COLLISIONS,
OID_GEN_NETWORK_LAYER_ADDRESSES,
};
MP_REG_ENTRY NICRegTable[] = {
// reg value name Offset in MP_ADAPTER Field size Default Value Min Max
{NDIS_STRING_CONST("VCI"), 0, MP_OFFSET(config.vci), MP_SIZE(config.vci), 0, 0, 65535},
{NDIS_STRING_CONST("VPI"), 0, MP_OFFSET(config.vpi), MP_SIZE(config.vpi), 0, 0, 255},
{NDIS_STRING_CONST("Encap"), 0, MP_OFFSET(Encap), MP_SIZE(Encap), 2, 0, 3},
};
BOOLEAN g_bDumpPackets = FALSE;
BOOLEAN g_fDiscardNonUnicastPackets = DISCARD_NON_UNICAST;
//-------------------------------------------------------------//
// //
// Pre defined LLC, SNAP and Other Headers for encapsulation //
// //
//-------------------------------------------------------------//
//
// Ethernet Encapsulation
//
UCHAR LLCSnapEthernet[] =
{
0xaa, 0xaa,0x03, // LLC
0x00, 0x80,0xc2, // OUI
0x00, 0x07, // PID
0x00, 0x00 // PAD
};
//
// Ip v4 encapsulation
//
UCHAR LLCSnapIpv4[8] =
{
0xaa, 0xaa,0x03, // LLC
0x00, 0x00,0x00, // OUI
0x08, 0x00 // PID
};
UCHAR gPaddingBytes[MINIMUM_ETHERNET_LENGTH] =
{
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0
};
//--------------------------------------------------------------------------------
// //
// miniports functions //
// //
//--------------------------------------------------------------------------------
VOID
epvcReturnPacketUsingAllocation(
IN PEPVC_I_MINIPORT pMiniport,
IN PNDIS_PACKET Packet,
OUT PNDIS_PACKET *ppOriginalPacket,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Extracts the original packet
frees all the ndis buffers in new packet
returns the original packet
Arguments:
Return Value:
--*/
{
PNDIS_PACKET pOrigPacket = NULL;
PEPVC_PKT_CONTEXT pPktContext = NULL;
TRACE (TL_T, TM_Recv , ("==>epvcReturnPacketUsingAllocation pMiniport %p, pPacket %p",
pMiniport,
Packet));
pPktContext = (PEPVC_PKT_CONTEXT )(Packet->MiniportReservedEx);
pOrigPacket = pPktContext->pOriginalPacket;
if (pMiniport->fDoIpEncapsulation == TRUE)
{
//
// Extract the lookaside buffer from the packet
//
PNDIS_BUFFER pBuffer = Packet->Private.Head;
PEPVC_IP_RCV_BUFFER pIpBuffer= pPktContext ->Stack.ipv4Recv.pIpBuffer;
if (pIpBuffer == NULL)
{
return ; // early return because of failure
}
ASSERT (pIpBuffer == NdisBufferVirtualAddress (pBuffer));
//
// Free the Lookaside Buffer
//
epvcFreeToNPagedLookasideList (&pMiniport->rcv.LookasideList,
(PVOID)pIpBuffer);
//
// In this case, we have allocated a new ndis buffer
// so delete it and free the local memory
epvcFreeBuffer (pBuffer);
//
// The original packet is unchanged and well./
//
}
else
{
//
// This code path is used in both Ethernet and Ethernet+LLC encaps
//
// We only need to free the head of the packet as that was allocated
// by us
PNDIS_BUFFER pNdisBuffer = Packet->Private.Head;
if (pNdisBuffer != NULL)
{
epvcFreeBuffer (pNdisBuffer);
}
}
epvcFreePacket(Packet,&pMiniport->PktPool.Recv);
*ppOriginalPacket = pOrigPacket;
TRACE (TL_T, TM_Recv , ("<==epvcReturnPacketUsingAllocation pOrigPacket %p",
*ppOriginalPacket));
return;
}
VOID
epvcReturnPacketUsingStacks (
IN PEPVC_I_MINIPORT pMiniport,
IN PNDIS_PACKET Packet,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
ipv4 - Restores the orginal Head and tail to this packet
Arguments:
Return Value:
--*/
{
PEPVC_PKT_CONTEXT pPktContext = NULL;
BOOLEAN Remaining = FALSE; // Unused
PNDIS_BUFFER pOldHead = NULL;
PNDIS_BUFFER pOldTail = NULL;
TRACE (TL_T, TM_Recv , ("==>epvcReturnPacketUsingStacks pMiniport %p, pPacket %p",
pMiniport,
Packet));
pPktContext = (PEPVC_PKT_CONTEXT ) NdisIMGetCurrentPacketStack(Packet, &Remaining);
if (pMiniport->fDoIpEncapsulation == TRUE)
{
//
// Extract the lookaside buffer from the packet
//
PNDIS_BUFFER pBuffer = Packet->Private.Head;
PEPVC_IP_RCV_BUFFER pIpBuffer= pPktContext ->Stack.ipv4Recv.pIpBuffer;
if (pIpBuffer == NULL)
{
return; // early return
}
//
// Extract the old head and tail from the packet
//
pOldHead = pIpBuffer->pOldHead;
pOldTail = pIpBuffer->pOldTail;
// check to see if we are in this code path because of a failure
if (pOldHead == NULL)
{
return; // early return
}
ASSERT (pOldHead != NULL);
ASSERT (pOldTail != NULL);
ASSERT (&pIpBuffer->u.Byte[0] == NdisBufferVirtualAddress (pBuffer));
//
// Set The original Head and Tail
//
Packet->Private.Head = pOldHead;
Packet->Private.Tail = pOldTail;
Packet->Private.ValidCounts= FALSE;
//
// Free the Lookaside Buffer
//
epvcFreeToNPagedLookasideList (&pMiniport->rcv.LookasideList,
(PVOID)pIpBuffer);
//
// In this case, we have allocated a new ndis buffer
// so delete it and free the local memory
epvcFreeBuffer (pBuffer);
}
else
{
//
// This code path is used in both Ethernet and Ethernet+LLC encaps
//
//
// We need to free the head as that was locally allocated/
// We need to revert back to the old Head and tail stored
// in the context
//
if (pPktContext->Stack.EthLLC.pOldHead == NULL)
{
return ; //early return
}
epvcFreeBuffer (Packet->Private.Head);
Packet->Private.Head = pPktContext->Stack.EthLLC.pOldHead;
Packet->Private.Tail = pPktContext->Stack.EthLLC.pOldTail;
Packet->Private.ValidCounts= FALSE;
}
TRACE (TL_T, TM_Recv , ("<==epvcReturnPacketUsingStacks ",pMiniport, Packet));
return;
}
VOID
epvcProcessReturnPacket (
IN PEPVC_I_MINIPORT pMiniport,
IN PNDIS_PACKET Packet,
OUT PPNDIS_PACKET ppOrigPacket,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Free all the locally allocated structures in the packet (packet , mdl, memory)
Also be able to handle failure cases
Arguments:
Return Value:
--*/
{
ENTER("epvcProcessReturnPacket", 0x7fafa89d)
PNDIS_PACKET pOrigPacket = NULL;
TRACE (TL_T, TM_Recv , ("==>epvcProcessReturnPacket pMiniport %p, pPacket %p",
pMiniport,
Packet));
if (Packet == NULL)
{
return;
}
//
// Packet stacking: Check if this packet belongs to us.
//
if (NdisGetPoolFromPacket(Packet) != pMiniport->PktPool.Recv.Handle)
{
//
// We reused the original packet in a receive indication.
//
epvcReturnPacketUsingStacks (pMiniport, Packet, pSR);
pOrigPacket = Packet;
}
else
{
//
// This is a packet allocated from this IM's receive packet pool.
// Reclaim our packet, and return the original to the driver below.
//
epvcReturnPacketUsingAllocation(pMiniport, Packet, &pOrigPacket, pSR);
}
//
// Update the output variable
//
if (ppOrigPacket)
{
*ppOrigPacket = pOrigPacket;
}
EXIT()
}
VOID
EpvcReturnPacket(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ENTER ("EpvcReturnPacket",0x58d2259e)
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT)MiniportAdapterContext;
PNDIS_PACKET pOrigPacket = NULL;
RM_DECLARE_STACK_RECORD (SR);
// Free all the locally allocated structures in the packet
//
epvcProcessReturnPacket (pMiniport, Packet, &pOrigPacket ,&SR);
// Return the original packet to ndis
//
if (pOrigPacket != NULL)
{
epvcReturnPacketToNdis(pMiniport, pOrigPacket, &SR);
}
else
{
ASSERT (!"Original packet is NULL\n");
}
EXIT();
}
NDIS_STATUS
MPTransferData(
OUT PNDIS_PACKET Packet,
OUT PUINT BytesTransferred,
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_HANDLE MiniportReceiveContext,
IN UINT ByteOffset,
IN UINT BytesToTransfer
)
/*++
Routine Description:
Miniport's transfer data handler.
Arguments:
Packet Destination packet
BytesTransferred Place-holder for how much data was copied
MiniportAdapterContext Pointer to the adapter structure
MiniportReceiveContext Context
ByteOffset Offset into the packet for copying data
BytesToTransfer How much to copy.
Return Value:
Status of transfer
--*/
{
PEPVC_I_MINIPORT pMiniport= (PEPVC_I_MINIPORT)MiniportAdapterContext;
NDIS_STATUS Status;
//
// Return, if the device is OFF
//
if (MiniportTestFlag (pMiniport, fMP_MiniportInitialized) == FALSE)
{
return NDIS_STATUS_FAILURE;
}
NdisTransferData(&Status,
pMiniport->pAdapter->bind.BindingHandle,
MiniportReceiveContext,
ByteOffset,
BytesToTransfer,
Packet,
BytesTransferred);
return(Status);
}
NDIS_STATUS
MPReset(
OUT PBOOLEAN AddressingReset,
IN NDIS_HANDLE MiniportAdapterContext
)
/*++
Routine Description:
Reset Handler. We just don't do anything.
Arguments:
AddressingReset To let NDIS know whether we need help from it with our reset
MiniportAdapterContext Pointer to our adapter
Return Value:
--*/
{
PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
*AddressingReset = FALSE;
return(NDIS_STATUS_SUCCESS);
}
//
// The functions that do the LBFO work and bundling.
// If LBFO is turned off, then the Set Scondary API is never called and there are no bundles
//
//--------------------------------------------------------------------------------
// //
// Intermediate Miniports. We have one instantiation per address family. //
// Entry points used by the RM Apis //
// //
// //
// //
//--------------------------------------------------------------------------------
PRM_OBJECT_HEADER
epvcIMiniportCreate(
PRM_OBJECT_HEADER pParentObject,
PVOID pCreateParams,
PRM_STACK_RECORD psr
)
/*++
Routine Description:
Allocate and initialize an object of type EPVC_I_MINIPORT.
Arguments:
pParentObject - Object that is to be the parent of the adapter.
pCreateParams - Actually a pointer to a EPVC_I_MINIPORT_PARAMS structure,
which contains information required to create the adapter.
Return Value:
Pointer to the allocated and initialized object on success.
NULL otherwise.
--*/
{
PEPVC_I_MINIPORT pIM;
PEPVC_I_MINIPORT_PARAMS pParams = (PEPVC_I_MINIPORT_PARAMS)pCreateParams;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
extern RM_STATIC_OBJECT_INFO EpvcGlobals_I_MiniportStaticInfo;
ENTER("IMiniport Create", 0x075b24c1);
TRACE (TL_V, TM_Pt, ("--> epvcIMiniportCreate") );
EPVC_ALLOCSTRUCT(pIM, TAG_MINIPORT );
do
{
if (pIM == NULL)
{
break;
}
EPVC_ZEROSTRUCT(pIM);
pIM->Hdr.Sig = TAG_MINIPORT;
//
// Do all the initialization work here
//
RmInitializeLock(
&pIM->Lock,
LOCKLEVEL_MINIPORT
);
RmInitializeHeader(
pParentObject,
&pIM->Hdr,
TAG_MINIPORT,
&pIM->Lock,
&EpvcGlobals_I_MiniportStaticInfo,
NULL,
psr
);
//
// Now initialize the adapter structure with the parameters
// that were passed in.
//
Status = epvcCopyUnicodeString(
&(pIM->ndis.DeviceName),
pParams->pDeviceName,
TRUE // Upcase
);
if (FAIL(Status))
{
pIM->ndis.DeviceName.Buffer=NULL; // so we don't try to free it later
break;
}
//
// initialize the informational stuff on the miniport
//
pIM->pAdapter = pParams->pAdapter;
pIM->info.PacketFilter = 0;
pIM->info.CurLookAhead = pParams->CurLookAhead;
pIM->info.NumberOfMiniports = pParams->NumberOfMiniports;
pIM->info.LinkSpeed = pParams->LinkSpeed.Outbound;
pIM->info.MediaState = pParams->MediaState;
//
// Start by using the real ATM card's MAC address
//
NdisMoveMemory(
&pIM->MacAddressEth,
&pIM->pAdapter->info.MacAddress,
sizeof(MAC_ADDRESS)
);
//
// Not Elan number zero so generate a locally
// administered address by manipulating the first two bytes.
//
pIM->MacAddressEth.Byte[0] =
0x02 | (((UCHAR)pIM->info.NumberOfMiniports & 0x3f) << 2);
pIM->MacAddressEth.Byte[1] =
(pIM->pAdapter->info.MacAddress.Byte[1] & 0x3f) |
((UCHAR)pIM->info.NumberOfMiniports & 0x3f);
pIM->info.MacAddressDummy = pIM->MacAddressEth;
pIM->info.MacAddressDummy.Byte[0]++;
pIM->info.MacAddressDummy.Byte[1]++;
pIM->info.MacAddressDummy.Byte[2]++;
{
//
// Create a Dummy Mac address for receive indications
//
pIM->info.MacAddressDest = pIM->MacAddressEth;
}
{
//
// Create an Ethernet Header to be used
//
PEPVC_ETH_HEADER pRcvEnetHeader = &pIM->RcvEnetHeader ;
pRcvEnetHeader->eh_daddr = pIM->info.MacAddressDest;
pRcvEnetHeader->eh_saddr = pIM->info.MacAddressDummy;
pRcvEnetHeader->eh_type = net_short (IP_PROT_TYPE );
}
pIM->info.McastAddrCount = 0;
Status = NDIS_STATUS_SUCCESS;
}
while(FALSE);
if (FAIL(Status))
{
if (pIM != NULL)
{
epvcIMiniportDelete ((PRM_OBJECT_HEADER) pIM, psr);
pIM = NULL;
}
}
TRACE (TL_V, TM_Pt, ("<-- epvcIMiniportCreate pIMiniport. %p",pIM) );
return (PRM_OBJECT_HEADER) pIM;
}
VOID
epvcIMiniportDelete (
PRM_OBJECT_HEADER pObj,
PRM_STACK_RECORD psr
)
/*++
Routine Description:
Free an object of type EPVC_I_MINIPORT.
Arguments:
pHdr - Actually a pointer to the EPVC_I_MINIPORT to be deleted.
--*/
{
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT) pObj;
TRACE (TL_V, TM_Pt, ("-- epvcIMiniportDelete pAdapter %p",pMiniport) );
pMiniport->Hdr.Sig = TAG_FREED;
EPVC_FREE (pMiniport);
}
BOOLEAN
epvcIMiniportCompareKey(
PVOID pKey,
PRM_HASH_LINK pItem
)
/*++
Routine Description:
Hash comparison function for EPVC_I_MINIPORT.
Arguments:
pKey - Points to a Epvc Protocol object.
pItem - Points to EPVC_I_MINIPORT.Hdr.HashLink.
Return Value:
TRUE IFF the key (adapter name) exactly matches the key of the specified
adapter object.
--*/
{
PEPVC_I_MINIPORT pIM = NULL;
PNDIS_STRING pName = (PNDIS_STRING) pKey;
BOOLEAN fCompare;
pIM = CONTAINING_RECORD(pItem, EPVC_I_MINIPORT, Hdr.HashLink);
//
// TODO: maybe case-insensitive compare?
//
if ( (pIM->ndis.DeviceName.Length == pName->Length)
&& NdisEqualMemory(pIM->ndis.DeviceName.Buffer, pName->Buffer, pName->Length))
{
return TRUE;
}
else
{
return FALSE;
}
TRACE (TL_V, TM_Pt, ("-- epvcProtocolCompareKey pIM %p, pKey, return %x",pIM, pKey, fCompare ) );
return fCompare;
}
ULONG
epvcIMiniportHash(
PVOID pKey
)
/*++
Routine Description:
Hash function responsible for returning a hash of pKey, which
we expect to be a pointer to an Epvc Protocol block.
Return Value:
ULONG-sized hash of the string.
--*/
{
TRACE(TL_T, TM_Mp, ("epvcIMiniportHash %x", pKey));
{
PNDIS_STRING pName = (PNDIS_STRING) pKey;
WCHAR *pwch = pName->Buffer;
WCHAR *pwchEnd = pName->Buffer + pName->Length/sizeof(*pwch);
ULONG Hash = 0;
for (;pwch < pwchEnd; pwch++)
{
Hash ^= (Hash<<1) ^ *pwch;
}
return Hash;
}
}
NDIS_STATUS
epvcTaskVcSetup(
IN struct _RM_TASK * pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Arguments:
UserParam for (Code == RM_TASKOP_START) : UnbindContext
--*/
{
ENTER("epvcTaskVcSetup", 0x64085960)
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT ) RM_PARENT_OBJECT(pTask);
PTASK_VC pTaskVc = (PTASK_VC) pTask;
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER)pMiniport->Hdr.pParentObject;
NDIS_HANDLE NdisVcHandle = NULL;
PCO_CALL_PARAMETERS pCallParameters = NULL;
enum
{
Stage_Start =0, // default
Stage_CreateVc,
Stage_MakeCall,
Stage_DeleteVc, // in case of failure
Stage_TaskCompleted,
Stage_End
}; // To be used in pTask->Hdr.State to indicate the state of the Task
TRACE ( TL_T, TM_Pt, ("==> epvcTaskVcSetup %x",pTask->Hdr.State ) );
switch (pTask->Hdr.State)
{
case Stage_Start:
{
LOCKOBJ (pMiniport, pSR);
if (epvcIsThisTaskPrimary ( pTask, &(PRM_TASK)(pMiniport->vc.pTaskVc)) == FALSE)
{
PRM_TASK pOtherTask = (PRM_TASK)(pMiniport->vc.pTaskVc);
RmTmpReferenceObject (&pOtherTask->Hdr, pSR);
//
// Set The state so we restart this code after main task completes
//
pTask->Hdr.State = Stage_Start;
UNLOCKOBJ(pMiniport, pSR);
RmPendTaskOnOtherTask (pTask, 0, pOtherTask, pSR);
RmTmpDereferenceObject(&pOtherTask->Hdr,pSR);
Status = NDIS_STATUS_PENDING;
break;
}
//
// We are the primary task
//
ASSERT (pMiniport->vc.pTaskVc == pTaskVc);
//
// Check to see if our work is already done
//
if (MiniportTestFlag(pMiniport, fMP_MakeCallSucceeded) == TRUE)
{
//
// Our work had been done. So break out and complete the task
//
Status = NDIS_STATUS_SUCCESS;
pTaskVc->ReturnStatus = NDIS_STATUS_SUCCESS;
pTask->Hdr.State = Stage_TaskCompleted;
UNLOCKOBJ(pMiniport, pSR);
break;
}
MiniportClearFlag (pMiniport,fMP_InfoCallClosed);
MiniportSetFlag (pMiniport, fMP_InfoMakingCall);
UNLOCKOBJ(pMiniport, pSR);
//
// Now begin the real work
//
//
// Set up the call parameters. If it fails ,then exit
//
epvcSetupMakeCallParameters(pMiniport, &pCallParameters);
if (pCallParameters == NULL)
{
Status = NDIS_STATUS_FAILURE;
pTaskVc->ReturnStatus = NDIS_STATUS_FAILURE;
pTask->Hdr.State = Stage_TaskCompleted;
break;
}
//
// Create Vc - Syncronous call
//
ASSERT (pAdapter->Hdr.Sig = TAG_ADAPTER);
Status = epvcCoCreateVc(pAdapter->bind.BindingHandle,
pMiniport->af.AfHandle OPTIONAL, // For CM signalling VCs
pMiniport,
&NdisVcHandle);
ASSERT (PEND(Status) == FALSE); // this is a synchronous call
if (FAIL(Status) == TRUE)
{
//
// We have failed. This task is done. There are not
// resources to be freed, although a flag has to be
// cleared
//
NdisVcHandle = NULL;
pMiniport->vc.VcHandle = NULL;
pTask->Hdr.State = Stage_TaskCompleted;
break;
}
ASSERT (Status == NDIS_STATUS_SUCCESS);
//
// Store the Vc Handle
//
LOCKOBJ (pMiniport, pSR);
pMiniport->vc.VcHandle = NdisVcHandle;
epvcLinkToExternal( &pMiniport->Hdr,
0xf52962f1,
(UINT_PTR)pMiniport->vc.VcHandle,
EPVC_ASSOC_MINIPORT_OPEN_VC,
" VcHandle %p\n",
pSR);
UNLOCKOBJ (pMiniport, pSR);
//
// Do a Make Call
//
pTask->Hdr.State = Stage_MakeCall;
RmSuspendTask(pTask, 0, pSR);
Status = epvcClMakeCall(NdisVcHandle,
pCallParameters,
NULL, //Party Context
NULL // PartyHandle
);
if (NDIS_STATUS_PENDING !=Status)
{
EpvcCoMakeCallComplete(Status,
pMiniport,
NULL,
0);
}
break;
}
case Stage_MakeCall:
{
//
// The make call has been completed.
// If we have succeeded then we update our flags
// and exit.
//
// If the make call has failed, then I need to delete the VC
//
ASSERT (NDIS_STATUS_CALL_ACTIVE != pTaskVc->ReturnStatus);
if (NDIS_STATUS_SUCCESS == pTaskVc->ReturnStatus)
{
LOCKOBJ(pMiniport, pSR);
MiniportSetFlag (pMiniport, fMP_MakeCallSucceeded);
MiniportClearFlag (pMiniport, fMP_InfoMakingCall);
UNLOCKOBJ (pMiniport, pSR);
}
else
{
NDIS_HANDLE VcHandle = NULL;
//
// Delete the VC, as we do not want a VC without an active
// Make call on it.
//
ASSERT (NDIS_STATUS_SUCCESS == pTaskVc->ReturnStatus);
LOCKOBJ(pMiniport, pSR);
VcHandle = pMiniport->vc.VcHandle;
epvcUnlinkFromExternal( &pMiniport->Hdr,
0xa914405a,
(UINT_PTR)pMiniport->vc.VcHandle,
EPVC_ASSOC_MINIPORT_OPEN_VC,
pSR);
pMiniport->vc.VcHandle = NULL;
UNLOCKOBJ (pMiniport, pSR);
TRACE (TL_I, TM_Mp,("Deleting Vc because of a failure in MakeCall"));
Status = epvcCoDeleteVc(VcHandle);
//
// TODO: Fix Failure case
//
ASSERT (NDIS_STATUS_SUCCESS == Status );
}
//
// This task is over. Now do the indications
//
pTask->Hdr.State = Stage_TaskCompleted;
Status = NDIS_STATUS_SUCCESS;
break;
}
case Stage_End:
{
Status = NDIS_STATUS_SUCCESS;
break;
}
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
} // end of switch
if ( Stage_TaskCompleted == pTask->Hdr.State )
{
pTask->Hdr.State = Stage_End;
ASSERT (NDIS_STATUS_PENDING !=Status );
//
// Do any cleanup indications to NDIS over here
//
epvcVcSetupDone ( pTaskVc, pMiniport);
LOCKOBJ(pMiniport, pSR);
pMiniport->vc.pTaskVc = NULL;
UNLOCKOBJ (pMiniport, pSR);
}
TRACE ( TL_T, TM_Mp, ("<== epvcTaskVcSetup , Status %x",Status) );
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
VOID
epvcVcSetupDone (
PTASK_VC pTaskVc,
PEPVC_I_MINIPORT pMiniport
)
/*++
Routine Description:
If the task was queued because of SetPacket Filter request then
this function completes the request.
If the task was run because of the Indicate Media Connect event, then
this thread indicates a Media Connect to NDIS
Arguments:
Status - Did the VcSetup Succeed or Fail
pTaskVc - Task in question
pMiniport - the Miniport that the task operated on
Return Value:
None:
--*/
{
if (TaskCause_NdisRequest == pTaskVc->Cause )
{
//
// Since requests are serialized, we don't acquire the lock
//
TRACE (TL_V, TM_Rq, ("Completing SetPacketFilter Request %x", pTaskVc->ReturnStatus ));
if (pTaskVc->ReturnStatus == NDIS_STATUS_SUCCESS)
{
pMiniport->info.PacketFilter = pTaskVc->PacketFilter;
}
NdisMSetInformationComplete (pMiniport->ndis.MiniportAdapterHandle, pTaskVc->ReturnStatus);
}
else
{
ASSERT (TaskCause_MediaConnect == pTaskVc->Cause );
pMiniport->info.MediaState = NdisMediaStateConnected;
NdisMIndicateStatus ( pMiniport->ndis.MiniportAdapterHandle,
NDIS_STATUS_MEDIA_CONNECT,
NULL,
0);
}
}
NDIS_STATUS
epvcTaskVcTeardown(
IN struct _RM_TASK * pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Arguments:
UserParam for (Code == RM_TASKOP_START) : UnbindContext
--*/
{
ENTER("epvcTaskVcTeardown", 0x68c96c4d)
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT ) RM_PARENT_OBJECT(pTask);
PTASK_VC pTaskVc = (PTASK_VC) pTask;
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER)pMiniport->Hdr.pParentObject;
NDIS_HANDLE NdisVcHandle = NULL;
PCO_CALL_PARAMETERS pCallParameters = NULL;
enum
{
Stage_Start =0, // default
Stage_CloseCallComplete,
Stage_DeleteVc,
Stage_TaskCompleted,
Stage_End
}; // To be used in pTask->Hdr.State to indicate the state of the Task
TRACE ( TL_T, TM_Pt, ("==> epvcTaskVcTeardown %x",pTask->Hdr.State ) );
switch (pTask->Hdr.State)
{
case Stage_Start:
{
LOCKOBJ (pMiniport, pSR);
if (epvcIsThisTaskPrimary ( pTask, &(PRM_TASK)(pMiniport->vc.pTaskVc)) == FALSE)
{
PRM_TASK pOtherTask = (PRM_TASK)(pMiniport->vc.pTaskVc);
RmTmpReferenceObject (&pOtherTask->Hdr, pSR);
//
// Set The state so we restart this code after main task completes
//
pTask->Hdr.State = Stage_Start;
UNLOCKOBJ(pMiniport, pSR);
RmPendTaskOnOtherTask (pTask, 0, pOtherTask, pSR);
RmTmpDereferenceObject(&pOtherTask->Hdr,pSR);
Status = NDIS_STATUS_PENDING;
break;
}
//
// We are the primary task
//
ASSERT (pMiniport->vc.pTaskVc == pTaskVc);
//
// Check to see if our work is already done
//
if (MiniportTestFlag(pMiniport, fMP_MakeCallSucceeded) == FALSE)
{
//
// Our work had been done. So break out and complete the task
//
Status = NDIS_STATUS_SUCCESS;
pTask->Hdr.State = Stage_TaskCompleted;
UNLOCKOBJ(pMiniport, pSR);
break;
}
MiniportClearFlag (pMiniport, fMP_MakeCallSucceeded);
MiniportSetFlag (pMiniport, fMP_InfoClosingCall);
UNLOCKOBJ(pMiniport, pSR);
//
// Now close the call - Asynchronously.
//
pTask->Hdr.State = Stage_CloseCallComplete;
RmSuspendTask (pTask, 0, pSR);
Status = epvcClCloseCall( pMiniport->vc.VcHandle);
if (NDIS_STATUS_PENDING != Status)
{
EpvcCoCloseCallComplete (Status,
pMiniport,
NULL
);
}
Status = NDIS_STATUS_PENDING;
break;
}
case Stage_CloseCallComplete:
{
NDIS_HANDLE VcHandle = NULL;
LOCKOBJ(pMiniport, pSR);
VcHandle = pMiniport->vc.VcHandle;
epvcUnlinkFromExternal(&pMiniport->Hdr,
0x5d7b5ea8,
(UINT_PTR)pMiniport->vc.VcHandle,
EPVC_ASSOC_MINIPORT_OPEN_VC,
pSR);
pMiniport->vc.VcHandle = NULL;
UNLOCKOBJ(pMiniport, pSR);
Status = epvcCoDeleteVc(VcHandle);
//
// This is an assertion because the DeleteVc cannot fail.
// We do a DeleteVc in one place only and it is serialized.
//
ASSERT (Status == NDIS_STATUS_SUCCESS);
pTask->Hdr.State = Stage_TaskCompleted;
break;
}
case Stage_End:
{
Status = NDIS_STATUS_SUCCESS;
break;
}
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
}
if (Stage_TaskCompleted == pTask->Hdr.State )
{
pTask->Hdr.State = Stage_End;
//
// Complete the request or the Media Disconnect;
//
epvcVcTeardownDone(pTaskVc, pMiniport);
LOCKOBJ (pMiniport, pSR);
//
// Update informational flags
//
MiniportClearFlag (pMiniport, fMP_InfoClosingCall);
MiniportSetFlag (pMiniport, fMP_InfoCallClosed);
pMiniport->vc.pTaskVc = NULL;
UNLOCKOBJ(pMiniport, pSR);
}
TRACE ( TL_T, TM_Mp, ("<== epvcTaskVcTeardown , Status %x",Status) );
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
VOID
epvcVcTeardownDone(
PTASK_VC pTaskVc,
PEPVC_I_MINIPORT pMiniport
)
{
TRACE ( TL_T, TM_Mp, ("==> epvcVcTeardownDone ") );
switch (pTaskVc->Cause)
{
case TaskCause_NdisRequest:
{
ASSERT (pTaskVc->ReturnStatus != NDIS_STATUS_PENDING);
//
// Since requests are serialized, we don't acquire the lock
//
pMiniport->info.PacketFilter = pTaskVc->PacketFilter;
NdisMSetInformationComplete(pMiniport->ndis.MiniportAdapterHandle,
pTaskVc->ReturnStatus);
break;
}
case TaskCause_MediaDisconnect:
{
pMiniport->info.MediaState = NdisMediaStateDisconnected;
epvcMIndicateStatus ( pMiniport,
NDIS_STATUS_MEDIA_DISCONNECT,
NULL,
0);
break;
}
default:
{
// Do nothing.
//
}
}
TRACE ( TL_T, TM_Mp, ("<== epvcVcTeardownDone ") );
}
NDIS_STATUS
EpvcInitialize(
OUT PNDIS_STATUS OpenErrorStatus,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_HANDLE WrapperConfigurationContext
)
/*++
Routine Description:
This is the initialize handler which gets called as a result of the BindAdapter handler
calling NdisIMInitializeDeviceInstanceEx(). The context parameter which we pass there is
the adapter structure which we retreive here. We also need to initialize the Power Management
variable.
LoadBalalncing- We keep a global list of all the passthru miniports installed and bundle
two of them together if they have the same BundleId (read from registry)
Arguments:
OpenErrorStatus Not used by us.
SelectedMediumIndex Place-holder for what media we are using
MediumArray Array of ndis media passed down to us to pick from
MediumArraySize Size of the array
MiniportAdapterHandle The handle NDIS uses to refer to us
WrapperConfigurationContext For use by NdisOpenConfiguration
Return Value:
NDIS_STATUS_SUCCESS unless something goes wrong
--*/
{
ENTER ("EpvcInitialize", 0xa935a2a5)
UINT i;
PEPVC_I_MINIPORT pMiniport = NULL;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
KIRQL OldIrql;
enum
{
Stage_Start,
Stage_AllocatedPacketPools,
Stage_AllocatedLookasideLists
};
ULONG State = Stage_Start;
RM_DECLARE_STACK_RECORD (SR);
TRACE (TL_T, TM_Mp, ("==>EpvcInitialize MiniportAdapterHandle %x", MiniportAdapterHandle));
//
// Start off by retrieving the adapter context and storing the Miniport handle in it
//
pMiniport = NdisIMGetDeviceContext(MiniportAdapterHandle);
if (pMiniport->Hdr.Sig != TAG_MINIPORT)
{
ASSERT (pMiniport->Hdr.Sig == TAG_MINIPORT);
return NDIS_STATUS_FAILURE;
}
pMiniport->ndis.MiniportAdapterHandle = MiniportAdapterHandle;
//
// Make sure the medium saved is one of the ones being offered
//
for (i = 0; i < MediumArraySize; i++)
{
if (MediumArray[i] == ATMEPVC_MP_MEDIUM )
{
*SelectedMediumIndex = i;
break;
}
}
if (i == MediumArraySize)
{
return(NDIS_STATUS_UNSUPPORTED_MEDIA);
}
//
// Set the attributes now. The NDIS_ATTRIBUTE_DESERIALIZE is the key. This enables us
// to make up-calls to NDIS w/o having to call NdisIMSwitchToMiniport/NdisIMQueueCallBack.
// This also forces us to protect our data using spinlocks where appropriate. Also in this
// case NDIS does not queue packets on out behalf. Since this is a very simple pass-thru
// miniport, we do not have a need to protect anything. However in a general case there
// will be a need to use per-adapter spin-locks for the packet queues at the very least.
//
NdisMSetAttributesEx(MiniportAdapterHandle,
pMiniport,
0, // CheckForHangTimeInSeconds
NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT |
NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT|
NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER |
NDIS_ATTRIBUTE_DESERIALIZE,
0);
//
// We are done, with the no failure stuff. From now on we need to undo
//
do
{
Status = epvcMiniportReadConfig(pMiniport, WrapperConfigurationContext,&SR );
if (Status != NDIS_STATUS_SUCCESS)
{
//
// Undo Configuration values
//
ASSERT (Status == NDIS_STATUS_SUCCESS);
break;
}
epvcInitializeMiniportParameters(pMiniport);
//
// allocate Packet pools.
//
Status = epvcInitializeMiniportPacketPools (pMiniport);
if (Status != NDIS_STATUS_SUCCESS)
{
ASSERT (Status == NDIS_STATUS_SUCCESS);
break;
}
State = Stage_AllocatedPacketPools;
//
// Allocate lookaside lists
//
epvcInitializeMiniportLookasideLists(pMiniport);
State = Stage_AllocatedLookasideLists;
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
TRACE (TL_T, TM_Mp, ("<==EpvcInitialize pMiniport %x, Status %x", pMiniport, Status ));
if (Status == NDIS_STATUS_SUCCESS)
{
BOOLEAN fSetDeInit = FALSE;
LOCKOBJ(pMiniport, &SR);
MiniportSetFlag(pMiniport, fMP_MiniportInitialized);
if (MiniportTestFlag (pMiniport, fMP_MiniportCancelInstance))
{
fSetDeInit = TRUE;
}
UNLOCKOBJ(pMiniport, &SR);
//
// Check to see if we have a DeInit Waiting for us.
// This will only be set if a Cancel Device Instance fails.
//
if (fSetDeInit == TRUE)
{
epvcSetEvent (&pMiniport->pnp.DeInitEvent);
}
}
else
{
//
// Undo Code
//
ASSERT (FAIL(Status) == TRUE);
switch (State)
{
case Stage_AllocatedLookasideLists:
epvcDeleteMiniportLookasideLists (pMiniport);
FALL_THROUGH
case Stage_AllocatedPacketPools:
epvcDeleteMiniportPacketPools(pMiniport);
FALL_THROUGH
default:
break;
}
}
RM_ASSERT_CLEAR(&SR);
EXIT();
return Status;
}
VOID
EpvcHalt(
IN NDIS_HANDLE MiniportAdapterContext
)
/*++
Routine Description:
Halt handler. All the hard-work for clean-up is done here.
Arguments:
MiniportAdapterContext Pointer to the Adapter
Return Value:
None.
--*/
{
ENTER("EpvcHalt",0x6b407ae1)
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT)MiniportAdapterContext;
PEPVC_ADAPTER pAdapter = pMiniport->pAdapter;
PRM_TASK pTask = NULL;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
RM_DECLARE_STACK_RECORD (SR);
TRACE (TL_V, TM_Mp, ("==>Epvc MPHaltMiniport"));
do
{
LOCKOBJ (pMiniport, &SR);
//
// Clear the flag so we can block all sends/receives/requests
//
MiniportClearFlag(pMiniport, fMP_MiniportInitialized);
MiniportSetFlag(pMiniport, fMP_InfoHalting);
//
// Ref the miniport, this indirectly refs the adpater as well
//
RmTmpReferenceObject (&pMiniport->Hdr, &SR);
//
// Kick of the miniport halt task and wait for it to complete
//
Status = epvcAllocateTask(
&pMiniport->Hdr, // pParentObject,
epvcTaskHaltMiniport, // pfnHandler,
0, // Timeout,
"Task: Halt Intermediate Miniport", // szDescription
&pTask,
&SR
);
if (FAIL(Status))
{
pTask = NULL;
break;
}
//
// Reference the task so it is around until our Wait for completion
// is complete
//
RmTmpReferenceObject (&pTask->Hdr, &SR);
UNLOCKOBJ (pMiniport, &SR);
//
// This Kicks of the task that will close the Call, Delete
// the VC and close the AF. We do this all synchronously
//
{
PTASK_HALT pHalt = (PTASK_HALT) pTask;
epvcInitializeEvent (&pHalt->CompleteEvent);
RmStartTask(pTask, 0, &SR);
TRACE (TL_V, TM_Mp, ("About to Wait - for Halt Complete Event"));
epvcWaitEvent (&pHalt->CompleteEvent, WAIT_INFINITE);
TRACE (TL_V, TM_Mp, ("Wait Complete- for Halt Complete Event"));
}
LOCKOBJ (pMiniport, &SR);
//
// Deref the task . Ref was made above.
//
RmTmpDereferenceObject (&pTask->Hdr, &SR);
} while (FALSE);
MiniportClearFlag(pMiniport, fMP_InfoHalting);
UNLOCKOBJ(pMiniport, &SR);
RmTmpDereferenceObject(&pMiniport->Hdr, &SR);
RM_ASSERT_CLEAR(&SR);
TRACE (TL_V, TM_Mp, ("<==Epvc MPHaltMiniport"));
}
VOID
epvcSetPacketFilterWorkItem (
PNDIS_WORK_ITEM pWorkItem,
PVOID Context
)
/*++
Routine Description:
Decrements the refcount on the filter and processes the new packet filter
Return Value:
None
--*/
{
ENTER ("epvcSetPacketFilterWorkItem ",0x3e1cdbba )
PEPVC_I_MINIPORT pMiniport = NULL;
PRM_TASK pTask = NULL;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
UINT Filter ;
RM_DECLARE_STACK_RECORD (SR);
do
{
pMiniport = CONTAINING_RECORD (pWorkItem,
EPVC_I_MINIPORT,
vc.PacketFilterWorkItem) ;
//
// Dereference the workitem off the miniport
//
epvcUnlinkFromExternal( &pMiniport->Hdr,
0xa1f5e3cc,
(UINT_PTR)pWorkItem,
EPVC_ASSOC_SET_FILTER_WORKITEM,
&SR);
//
// Start the task to create or delete the VC
//
Filter = pMiniport->vc.NewFilter ;
//
// If this is a repition, then succeed it synchronously
//
if (Filter == pMiniport->info.PacketFilter)
{
Status = NDIS_STATUS_SUCCESS;
break;
}
LOCKOBJ(pMiniport, &SR);
//
// Are we moving to a Zero filter value
//
if (Filter == 0)
{
//
// Delete the Vc, so that we stop doing any receives
//
Status = epvcAllocateTask(
&pMiniport->Hdr, // pParentObject,
epvcTaskVcTeardown, // pfnHandler,
0, // Timeout,
"Task: Delete Vc", // szDescription
&pTask,
&SR
);
}
else
{
//
// We are moving a non-zero values
//
//
// Create the Vc, so that we can send
//
Status = epvcAllocateTask(
&pMiniport->Hdr, // pParentObject,
epvcTaskVcSetup, // pfnHandler,
0, // Timeout,
"Task: Create Vc", // szDescription
&pTask,
&SR
);
}
UNLOCKOBJ(pMiniport, &SR);
if (FAIL(Status) == TRUE)
{
// Ugly situation. We'll just leave things as they are...
//
pTask = NULL;
TR_WARN(("FATAL: couldn't allocate create/ delete Vc task!\n"));
ASSERT (0);
break;
}
//
// Update the cause if the task
//
((PTASK_VC)pTask)->Cause = TaskCause_NdisRequest;
((PTASK_VC)pTask)->PacketFilter = Filter ;
RmStartTask(pTask, 0, &SR);
Status = NDIS_STATUS_PENDING;
} while (FALSE);
//
// complete the request if the task has not been started
//
if (PEND(Status) != TRUE)
{
NdisMSetInformationComplete (pMiniport->ndis.MiniportAdapterHandle, Status);
}
EXIT();
}
NDIS_STATUS
epvcSetPacketFilter(
IN PEPVC_I_MINIPORT pMiniport,
IN ULONG Filter,
PRM_STACK_RECORD pSR
)
/*++
Routine Description:
This routine is called when a miniport get a set packet filter.
It validates the arguments, If all is well then it process the request
For a non-zero filter, a create VC and a Make call is done.
For a zero filter, the call is closed and the Vc Deleted
Return Value:
NDIS_STATUS_SUCCESS unless something goes wrong
--*/
{
ENTER ("epvcSetPacketFilter", 0x97c6b961)
NDIS_STATUS Status = NDIS_STATUS_PENDING;
PNDIS_WORK_ITEM pSetFilterWorItem = &pMiniport->vc.PacketFilterWorkItem;
PRM_TASK pTask = NULL;
TRACE (TL_T, TM_Mp, ("==>epvcSetPacketFilter Filter %X", Filter ));
do
{
LOCKOBJ (pMiniport, pSR);
epvcLinkToExternal( &pMiniport->Hdr,
0x20bc1fbf,
(UINT_PTR)pSetFilterWorItem,
EPVC_ASSOC_SET_FILTER_WORKITEM,
" PacketFilterWorkItem %p\n",
pSR);
//
// Update the cause of the task
//
UNLOCKOBJ(pMiniport, pSR);
//
// Now schedule the work item so it runs at passive level and pass the Vc as
// an argument
//
pMiniport->vc.NewFilter = Filter;
NdisInitializeWorkItem ( pSetFilterWorItem ,
(NDIS_PROC)epvcSetPacketFilterWorkItem ,
(PVOID)pTask );
NdisScheduleWorkItem (pSetFilterWorItem );
Status = NDIS_STATUS_PENDING;
} while (FALSE);
TRACE (TL_T, TM_Mp, ("<==epvcSetPacketFilter %x", Status));
EXIT();
return Status;
}
NDIS_STATUS
EpvcMpQueryInformation(
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG BytesWritten,
OUT PULONG BytesNeeded
)
/*++
Routine Description:
The QueryInformation Handler for the virtual miniport.
Arguments:
MiniportAdapterContext - a pointer to the Elan.
Oid - the NDIS_OID to process.
InformationBuffer - a pointer into the NdisRequest->InformationBuffer
into which store the result of the query.
InformationBufferLength - a pointer to the number of bytes left in the
InformationBuffer.
BytesWritten - a pointer to the number of bytes written into the
InformationBuffer.
BytesNeeded - If there is not enough room in the information
buffer then this will contain the number of bytes
needed to complete the request.
Return Value:
The function value is the status of the operation.
--*/
{
ENTER ("EpvcMpQueryInformation", 0x3da2473b)
UINT BytesLeft = InformationBufferLength;
PUCHAR InfoBuffer = (PUCHAR)(InformationBuffer);
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
NDIS_MEDIUM Medium;
PEPVC_I_MINIPORT pMiniport = NULL;
PEPVC_ADAPTER pAdapter= NULL;
ULONG GenericULong =0;
USHORT GenericUShort=0;
UCHAR GenericArray[6];
UINT MoveBytes = sizeof(ULONG);
PVOID MoveSource = (PVOID)(&GenericULong);
ULONG i=0;
BOOLEAN IsShuttingDown = FALSE;
RM_DECLARE_STACK_RECORD (SR);
TRACE(TL_T, TM_Rq, ("==>EpvcMpQueryInformation pMiniport %x, Oid, Buffer %x, Length, %x",
pMiniport,
Oid,
InformationBuffer,
InformationBufferLength));
pMiniport = (PEPVC_I_MINIPORT)MiniportAdapterContext;
LOCKOBJ(pMiniport, &SR);
IsShuttingDown = (! MiniportTestFlag(pMiniport, fMP_MiniportInitialized));
pAdapter = pMiniport->pAdapter;
UNLOCKOBJ(pMiniport,&SR);
//
// Switch on request type
//
switch (Oid)
{
case OID_GEN_MAC_OPTIONS:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_MAC_OPTIONS"));
GenericULong =
NDIS_MAC_OPTION_NO_LOOPBACK;
break;
case OID_GEN_SUPPORTED_LIST:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_SUPPORTED_LIST"));
MoveSource = (PVOID)(EthernetSupportedOids);
MoveBytes = sizeof(EthernetSupportedOids);
break;
case OID_GEN_HARDWARE_STATUS:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_HARDWARE_STATUS"));
HardwareStatus = NdisHardwareStatusReady;
MoveSource = (PVOID)(&HardwareStatus);
MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_MEDIA_CONNECT_STATUS"));
MoveSource = (PVOID)(&pMiniport->info.MediaState);
MoveBytes = sizeof(NDIS_MEDIA_STATE);
break;
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_MEDIA_SUPPORTED"));
Medium = ATMEPVC_MP_MEDIUM;
MoveSource = (PVOID) (&Medium);
MoveBytes = sizeof(NDIS_MEDIUM);
break;
case OID_GEN_MAXIMUM_LOOKAHEAD:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_MAXIMUM_LOOKAHEAD"));
GenericULong = pMiniport->info.CurLookAhead;
break;
case OID_GEN_CURRENT_LOOKAHEAD:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_CURRENT_LOOKAHEAD"));
GenericULong = pMiniport->info.CurLookAhead ;
break;
case OID_GEN_MAXIMUM_FRAME_SIZE:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_MAXIMUM_FRAME_SIZE"));
//
// Similiar to AtmLane . Take the size of the Ethernet frame and strip the
// ethernet header off.
//
GenericULong = EPVC_MAX_FRAME_SIZE - EPVC_ETH_HEADERSIZE ;
break;
case OID_GEN_MAXIMUM_TOTAL_SIZE:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_MAXIMUM_TOTAL_SIZE"));
//
// This value is inclusive of headers
//
GenericULong = EPVC_MAX_FRAME_SIZE;
break;
case OID_GEN_TRANSMIT_BLOCK_SIZE:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_TRANSMIT_BLOCK_SIZE"));
//
// This is inclusive of headers.
//
GenericULong = EPVC_MAX_FRAME_SIZE;
break;
case OID_GEN_RECEIVE_BLOCK_SIZE:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_RECEIVE_BLOCK_SIZE"));
GenericULong = EPVC_MAX_FRAME_SIZE ;
break;
case OID_GEN_MAXIMUM_SEND_PACKETS:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_MAXIMUM_SEND_PACKETS"));
GenericULong = 32; // XXX What is our limit? From adapter?
break;
case OID_GEN_LINK_SPEED:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_LINK_SPEED"));
GenericULong = pMiniport->info.LinkSpeed;
break;
case OID_GEN_TRANSMIT_BUFFER_SPACE:
case OID_GEN_RECEIVE_BUFFER_SPACE:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_RECEIVE_BUFFER_SPACE"));
GenericULong = 32 * 1024; // XXX What should this really be?
break;
case OID_GEN_VENDOR_ID:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_VENDOR_ID"));
NdisMoveMemory(
(PVOID)&GenericULong,
&pMiniport->MacAddressEth,
3
);
GenericULong &= 0xFFFFFF00;
MoveSource = (PVOID)(&GenericULong);
MoveBytes = sizeof(GenericULong);
break;
case OID_GEN_VENDOR_DESCRIPTION:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_VENDOR_DESCRIPTION"));
MoveSource = (PVOID)"Microsoft ATM Ethernet Emulation";
MoveBytes = 28;
break;
case OID_GEN_DRIVER_VERSION:
case OID_GEN_VENDOR_DRIVER_VERSION:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_DRIVER_VERSION"));
GenericUShort = ((USHORT)5 << 8) | 0;
MoveSource = (PVOID)(&GenericUShort);
MoveBytes = sizeof(GenericUShort);
break;
case OID_802_3_PERMANENT_ADDRESS:
case OID_802_3_CURRENT_ADDRESS:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_802_3_CURRENT_ADDRESS"));
NdisMoveMemory((PCHAR)GenericArray,
&pMiniport->MacAddressEth,
sizeof(MAC_ADDRESS));
MoveSource = (PVOID)(GenericArray);
MoveBytes = sizeof(MAC_ADDRESS);
break;
case OID_802_3_MULTICAST_LIST:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_802_3_MULTICAST_LIST"));
MoveSource = (PVOID) &pMiniport->info.McastAddrs[0];
MoveBytes = pMiniport->info.McastAddrCount * sizeof(MAC_ADDRESS);
break;
case OID_802_3_MAXIMUM_LIST_SIZE:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_802_3_MAXIMUM_LIST_SIZE"));
GenericULong = MCAST_LIST_SIZE;
break;
case OID_GEN_XMIT_OK:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_XMIT_OK"));
GenericULong = (UINT)(pMiniport->count.FramesXmitOk);
break;
case OID_GEN_RCV_OK:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_RCV_OK"));
GenericULong = (UINT)(pMiniport->count.FramesRecvOk);
break;
case OID_GEN_RCV_ERROR:
TRACE (TL_V, TM_Rq,(" Miniport Query OID_GEN_RCV_OK"));
GenericULong = pMiniport->count.RecvDropped ;
break;
case OID_GEN_XMIT_ERROR:
case OID_GEN_RCV_NO_BUFFER:
case OID_802_3_RCV_ERROR_ALIGNMENT:
case OID_802_3_XMIT_ONE_COLLISION:
case OID_802_3_XMIT_MORE_COLLISIONS:
TRACE (TL_V, TM_Rq,(" Miniport Query - Unimplemented Stats Oid"));
GenericULong = 0;
break;
default:
StatusToReturn = NDIS_STATUS_INVALID_OID;
break;
}
if (StatusToReturn == NDIS_STATUS_SUCCESS)
{
if (MoveBytes > BytesLeft)
{
//
// Not enough room in InformationBuffer. Punt
//
*BytesNeeded = MoveBytes;
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
}
else
{
//
// Store and print result.
//
NdisMoveMemory(InfoBuffer, MoveSource, MoveBytes);
TRACE (TL_V, TM_Rq, ("Query Request Oid %x", Oid));
DUMPDW( TL_V, TM_Rq, MoveSource, MoveBytes);
(*BytesWritten) = MoveBytes;
}
}
TRACE(TL_T, TM_Rq, ("<==EpvcMpQueryInformation Status %x",StatusToReturn));
RM_ASSERT_CLEAR(&SR);
return StatusToReturn;
}
NDIS_STATUS
EpvcMpSetInformation(
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG BytesRead,
OUT PULONG BytesNeeded
)
/*++
Routine Description:
Handles a set operation for a single OID.
Arguments:
MiniportAdapterContext - a pointer to the Elan.
Oid - the NDIS_OID to process.
InformationBuffer - Holds the data to be set.
InformationBufferLength - The length of InformationBuffer.
BytesRead - If the call is successful, returns the number
of bytes read from InformationBuffer.
BytesNeeded - If there is not enough data in InformationBuffer
to satisfy the OID, returns the amount of storage
needed.
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_INVALID_LENGTH
NDIS_STATUS_INVALID_OID
--*/
{
ENTER ("EpvcMpSetInformation", 0x619a7528)
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
UINT BytesLeft = InformationBufferLength;
PUCHAR InfoBuffer = (PUCHAR)(InformationBuffer);
UINT OidLength;
ULONG LookAhead;
ULONG Filter;
PEPVC_I_MINIPORT pMiniport = NULL;
PEPVC_ADAPTER pAdapter = NULL;
BOOLEAN IsShuttingDown = FALSE;
RM_DECLARE_STACK_RECORD (SR);
TRACE(TL_T, TM_Mp, ("==>EpvcMpSetInformation pMiniport %x, Oid, Buffer %x, Length, %x",
pMiniport,
Oid,
InformationBuffer,
InformationBufferLength));
pMiniport = (PEPVC_I_MINIPORT)MiniportAdapterContext;
LOCKOBJ(pMiniport, &SR);
IsShuttingDown =(! MiniportTestFlag(pMiniport, fMP_MiniportInitialized));
pAdapter = pMiniport->pAdapter;
UNLOCKOBJ(pMiniport,&SR);
if (IsShuttingDown)
{
TRACE (TL_I, TM_Mp,(" Miniport shutting down. Trivially succeeding Set OID %x \n", Oid ));
*BytesRead = 0;
*BytesNeeded = 0;
StatusToReturn = NDIS_STATUS_SUCCESS;
return (StatusToReturn);
}
//
// Get Oid and Length of request
//
OidLength = BytesLeft;
switch (Oid)
{
case OID_802_3_MULTICAST_LIST:
TRACE (TL_V, TM_Rq,(" Miniport Set OID_802_3_MULTICAST_LIST"));
if (OidLength % sizeof(MAC_ADDRESS))
{
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
*BytesRead = 0;
*BytesNeeded = 0;
break;
}
if (OidLength > (MCAST_LIST_SIZE * sizeof(MAC_ADDRESS)))
{
StatusToReturn = NDIS_STATUS_MULTICAST_FULL;
*BytesRead = 0;
*BytesNeeded = 0;
break;
}
NdisZeroMemory(
&pMiniport->info.McastAddrs[0],
MCAST_LIST_SIZE * sizeof(MAC_ADDRESS)
);
NdisMoveMemory(
&pMiniport->info.McastAddrs[0],
InfoBuffer,
OidLength
);
pMiniport->info.McastAddrCount = OidLength / sizeof(MAC_ADDRESS);
break;
case OID_GEN_CURRENT_PACKET_FILTER:
TRACE (TL_V, TM_Rq,(" Miniport Set OID_GEN_CURRENT_PACKET_FILTER"));
//
// Verify length
//
if (OidLength != sizeof(ULONG))
{
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
*BytesRead = 0;
*BytesNeeded = sizeof(ULONG);
ASSERT (0);
break;
}
BytesLeft = sizeof (ULONG);
//
// Store the new value.
//
NdisMoveMemory(&Filter, InfoBuffer, BytesLeft );
//
// Don't allow promisc mode, because we can't support that.
//
if (Filter & NDIS_PACKET_TYPE_PROMISCUOUS)
{
StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
break;
}
StatusToReturn = epvcSetPacketFilter(pMiniport, Filter, &SR);
break;
case OID_802_5_CURRENT_FUNCTIONAL:
case OID_802_5_CURRENT_GROUP:
TRACE (TL_V, TM_Rq,(" Miniport Set OID_802_5_CURRENT_GROUP"));
// XXX just accept whatever for now ???
break;
case OID_GEN_CURRENT_LOOKAHEAD:
TRACE (TL_V, TM_Rq,(" Miniport Set OID_GEN_CURRENT_LOOKAHEAD"));
//
// Verify length
//
if (OidLength != 4)
{
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
*BytesRead = 0;
*BytesNeeded = 0;
break;
}
//
// Store the new value.
//
NdisMoveMemory(&LookAhead, InfoBuffer, 4);
ASSERT (pMiniport->pAdapter != NULL);
if (LookAhead <= pAdapter->info.MaxAAL5PacketSize)
{
pMiniport->info.CurLookAhead = LookAhead;
TRACE (TL_V, TM_Mp, ("New Lookahead size %x \n",pMiniport->info.CurLookAhead ));
}
else
{
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
}
break;
case OID_GEN_NETWORK_LAYER_ADDRESSES:
TRACE (TL_V, TM_Rq,(" Miniport Set OID_GEN_NETWORK_LAYER_ADDRESSES"));
StatusToReturn = epvcMpSetNetworkAddresses(
pMiniport,
InformationBuffer,
InformationBufferLength,
&SR,
BytesRead,
BytesNeeded);
break;
default:
StatusToReturn = NDIS_STATUS_INVALID_OID;
*BytesRead = 0;
*BytesNeeded = 0;
break;
}
if (StatusToReturn == NDIS_STATUS_SUCCESS)
{
*BytesRead = BytesLeft;
*BytesNeeded = 0;
DUMPDW( TL_V, TM_Rq, InformationBuffer, *BytesRead );
}
TRACE(TL_T, TM_Mp, ("<==EpvcMpSetInformation Status %x",StatusToReturn));
RM_ASSERT_CLEAR(&SR);
return StatusToReturn;
}
VOID
epvcMPLocalRequestComplete (
PEPVC_NDIS_REQUEST pEpvcRequest,
NDIS_STATUS Status
)
/*++
Routine Description:
Miniport's local Request Completion handler for the occasion
when a locally allocated NdisRequest was sent to the miniport below us.
We look up to see if a request to our miniport edge initiated this request.
If so, we complete the Set/Query
Assumes that the epvcRequest was allocated from the HEAP
Arguments:
pEpvcRequest - Locally allocated Request structure
Return Value:
--*/
{
ENTER("epvcMPLocalRequestComplete ", 0x77d107ae)
PEPVC_I_MINIPORT pMiniport = pEpvcRequest->pMiniport;
RM_DECLARE_STACK_RECORD (SR);
//
// First complete the request that we have pended
//
do
{
if (pMiniport == NULL || pEpvcRequest->fPendedRequest == FALSE)
{
//
// No pended request to complete
//
break;
}
if (pEpvcRequest->fSet == TRUE)
{
NdisMSetInformationComplete (pMiniport->ndis.MiniportAdapterHandle,
Status);
}
else
{
NdisMQueryInformationComplete (pMiniport->ndis.MiniportAdapterHandle,
Status);
}
} while (FALSE);
if (pMiniport != NULL)
{
//
// Deref the miniport
//
epvcUnlinkFromExternal( &pMiniport->Hdr, //pHdr
0xaa625b37, // Luid
(UINT_PTR)pEpvcRequest,// External entity
EPVC_ASSOC_MINIPORT_REQUEST, // AssocID
&SR
);
}
//
// now free the memory that was allocated.
//
NdisFreeMemory (pEpvcRequest, sizeof (*pEpvcRequest), 0);
}
NDIS_STATUS
epvcMpSetNetworkAddresses(
IN PEPVC_I_MINIPORT pMiniport,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
IN PRM_STACK_RECORD pSR,
OUT PULONG BytesRead,
OUT PULONG BytesNeeded
)
/*++
Routine Description:
Called when the protocol above us wants to let us know about
the network address(es) assigned to this interface. If this is TCP/IP,
then we reformat and send a request to the ATM Call Manager to set
its atmfMyIpNmAddress object. We pick the first IP address given to us.
Arguments:
pMiniport - Pointer to the ELAN
InformationBuffer - Holds the data to be set.
InformationBufferLength - The length of InformationBuffer.
BytesRead - If the call is successful, returns the number
of bytes read from InformationBuffer.
BytesNeeded - If there is not enough data in InformationBuffer
to satisfy the OID, returns the amount of storage
needed.
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
NDIS_STATUS_INVALID_LENGTH
--*/
{
ENTER("epvcMpSetNetworkAddresses" , 0x385441e2)
NETWORK_ADDRESS_LIST UNALIGNED * pAddrList = NULL;
NETWORK_ADDRESS UNALIGNED * pAddr = NULL;
NETWORK_ADDRESS_IP UNALIGNED * pIpAddr= NULL;
ULONG Size;
PUCHAR pNetworkAddr = NULL;
NDIS_HANDLE NdisAdapterHandle;
NDIS_HANDLE NdisAfHandle;
NDIS_STATUS Status;
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER)pMiniport->pAdapter;
//
// Initialize.
//
*BytesRead = 0;
Status = NDIS_STATUS_SUCCESS;
pAddrList = (NETWORK_ADDRESS_LIST UNALIGNED *)InformationBuffer;
do
{
*BytesNeeded = sizeof(*pAddrList) -
FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) +
sizeof(NETWORK_ADDRESS) -
FIELD_OFFSET(NETWORK_ADDRESS, Address);
if (InformationBufferLength < *BytesNeeded)
{
Status = NDIS_STATUS_INVALID_LENGTH;
break;
}
if (pAddrList->AddressType != NDIS_PROTOCOL_ID_TCP_IP)
{
// Not interesting.
break;
}
if (pAddrList->AddressCount <= 0)
{
Status = NDIS_STATUS_INVALID_DATA;
break;
}
pAddr = (NETWORK_ADDRESS UNALIGNED *)&pAddrList->Address[0];
if ((pAddr->AddressLength > InformationBufferLength - *BytesNeeded) ||
(pAddr->AddressLength == 0))
{
Status = NDIS_STATUS_INVALID_LENGTH;
break;
}
if (pAddr->AddressType != NDIS_PROTOCOL_ID_TCP_IP)
{
// Not interesting.
break;
}
if (pAddr->AddressLength < sizeof(NETWORK_ADDRESS_IP))
{
Status = NDIS_STATUS_INVALID_LENGTH;
break;
}
pIpAddr = (NETWORK_ADDRESS_IP UNALIGNED *)&pAddr->Address[0];
//
// Allocate an NDIS request to send down to the call manager.
//
Size = sizeof(pIpAddr->in_addr);
Status = epvcAllocateMemoryWithTag(&pNetworkAddr, Size, TAG_DEFAULT );
if ((FAIL(Status) == TRUE) || pNetworkAddr == NULL)
{
Status = NDIS_STATUS_RESOURCES;
pNetworkAddr = NULL;
break;
}
//
// Copy the network address in.
//
NdisMoveMemory(pNetworkAddr, &pIpAddr->in_addr, sizeof(pIpAddr->in_addr));
TRACE (TL_V, TM_Mp, (" Set network layer addr: length %d\n", pAddr->AddressLength));
#if DBG
if (pAddr->AddressLength >= 4)
{
TRACE(TL_V, TM_Mp, ("Network layer addr: %d.%d.%d.%d\n",
pNetworkAddr[0],
pNetworkAddr[1],
pNetworkAddr[2],
pNetworkAddr[3]));
}
#endif // DBG
//
// Send off the request.
//
{
PEPVC_NDIS_REQUEST pRequest;
do
{
Status = epvcAllocateMemoryWithTag (&pRequest, sizeof(*pRequest), TAG_DEFAULT) ;
if (Status != NDIS_STATUS_SUCCESS)
{
pRequest = NULL;
break;
}
//
// There is no failure code path in prepareandsendrequest.
// Our completion handler will get called and free the memory
//
Status = epvcPrepareAndSendNdisRequest(
pAdapter,
pRequest,
epvcMPLocalRequestComplete,
OID_ATM_MY_IP_NM_ADDRESS,
pNetworkAddr,
sizeof(pIpAddr->in_addr),
NdisRequestSetInformation,
pMiniport,
TRUE, // We have Pended a Request
TRUE, // The Pended request is a Set
pSR
);
} while (FALSE);
}
break;
}
while (FALSE);
EXIT();
return (Status);
}
VOID
epvcSetupMakeCallParameters(
PEPVC_I_MINIPORT pMiniport,
PCO_CALL_PARAMETERS *ppCallParameters
)
/*++
Routine Description:
Sets up the Call parameters after reading the information
from the miniport block
Arguments:
pMiniport - Miniport in question
ppCallParameter - Location of Call Parameters
Return Value:
return value *ppCallParamter is NULL on Failure
--*/
{
ULONG RequestSize = 0;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PCO_CALL_PARAMETERS pCallParameters = NULL;
PCO_CALL_MANAGER_PARAMETERS pCallMgrParameters = NULL;
PCO_MEDIA_PARAMETERS pMediaParameters = NULL;
PATM_MEDIA_PARAMETERS pAtmMediaParameters = NULL;
do
{
Status = epvcAllocateMemoryWithTag( &pCallParameters,
CALL_PARAMETER_SIZE,
TAG_DEFAULT);
if (Status != NDIS_STATUS_SUCCESS || pCallParameters == NULL)
{
pCallParameters = NULL;
Status = NDIS_STATUS_RESOURCES;
break;
}
NdisZeroMemory (pCallParameters, CALL_PARAMETER_SIZE);
//
// Distribute space and link up pointers amongst the various
// structures for the PVC.
//
// pCallParameters------->+----------------------------+
// | CO_CALL_PARAMETERS |
// pCallMgrParameters---->+----------------------------+
// | CO_CALL_MANAGER_PARAMETERS |
// pMediaParameters------>+----------------------------+
// | CO_MEDIA_PARAMETERS |
// pAtmMediaParameters--->+----------------------------+
// | ATM_MEDIA_PARAMETERS |
// +----------------------------+
//
pCallMgrParameters = (PCO_CALL_MANAGER_PARAMETERS)
((PUCHAR)pCallParameters +
sizeof(CO_CALL_PARAMETERS));
pCallParameters->CallMgrParameters = pCallMgrParameters;
pCallMgrParameters->CallMgrSpecific.ParamType = 0;
pCallMgrParameters->CallMgrSpecific.Length = 0;
pMediaParameters = (PCO_MEDIA_PARAMETERS)
pCallMgrParameters->CallMgrSpecific.Parameters;
pCallParameters->MediaParameters = pMediaParameters;
pAtmMediaParameters = (PATM_MEDIA_PARAMETERS)
pMediaParameters->MediaSpecific.Parameters;
//
// Call Manager generic flow paramters:
//
pCallMgrParameters->Transmit.TokenRate =
pMiniport->pAdapter->info.LinkSpeed.Outbound/8*100; // cnvt decibits to bytes
pCallMgrParameters->Transmit.PeakBandwidth =
pMiniport->pAdapter->info.LinkSpeed.Outbound/8*100; // cnvt decibits to bytes
pCallMgrParameters->Transmit.ServiceType = SERVICETYPE_BESTEFFORT;
pCallMgrParameters->Receive.TokenRate =
pMiniport->pAdapter->info.LinkSpeed.Inbound/8*100; // cnvt decibits to bytes
pCallMgrParameters->Receive.PeakBandwidth =
pMiniport->pAdapter->info.LinkSpeed.Inbound/8*100; // cnvt decibits to bytes
pCallMgrParameters->Receive.ServiceType = SERVICETYPE_BESTEFFORT;
//
// use 1516 per spec
//
pCallMgrParameters->Transmit.TokenBucketSize =
pCallMgrParameters->Transmit.MaxSduSize =
pCallMgrParameters->Receive.TokenBucketSize =
pCallMgrParameters->Receive.MaxSduSize =
1516;
//
// PVC Generic and ATM-specific Media Parameters
//
pMediaParameters->Flags = TRANSMIT_VC | RECEIVE_VC;
pMediaParameters->MediaSpecific.ParamType = ATM_MEDIA_SPECIFIC;
pMediaParameters->MediaSpecific.Length = sizeof(ATM_MEDIA_PARAMETERS);
pAtmMediaParameters->ConnectionId.Vpi = pMiniport->config.vpi; //0
pAtmMediaParameters->ConnectionId.Vci = pMiniport->config.vci;
TRACE (TL_I, TM_Mp, ("Miniport Configuration vci %x ,vpi %x",
pMiniport->config.vci ,
pMiniport->config.vpi ));
ASSERT (pMiniport->MaxAcceptablePkt > 1000);
pAtmMediaParameters->AALType = AAL_TYPE_AAL5;
pAtmMediaParameters->Transmit.PeakCellRate =
LINKSPEED_TO_CPS(pMiniport->pAdapter->info.LinkSpeed.Outbound);
pAtmMediaParameters->Transmit.MaxSduSize = pMiniport->MaxAcceptablePkt ;
pAtmMediaParameters->Transmit.ServiceCategory =
ATM_SERVICE_CATEGORY_UBR;
pAtmMediaParameters->Receive.PeakCellRate =
LINKSPEED_TO_CPS(pMiniport->pAdapter->info.LinkSpeed.Outbound);
pAtmMediaParameters->Receive.MaxSduSize = pMiniport->MaxAcceptablePkt ;
pAtmMediaParameters->Receive.ServiceCategory =
ATM_SERVICE_CATEGORY_UBR;
//
// Set PVC flag here
//
pCallParameters->Flags |= PERMANENT_VC;
} while (FALSE);
if (Status == NDIS_STATUS_SUCCESS && pCallParameters != NULL)
{
//
// Set up the return value here
//
*ppCallParameters = pCallParameters;
}
else
{
//
// Clear the Failure case
//
*ppCallParameters = NULL;
}
}
VOID
epvcRefRecvPkt(
PNDIS_PACKET pNdisPacket,
PRM_OBJECT_HEADER pHdr // either an adapter or a miniport
)
{
// The following macros are just so that we can make
// the proper debug association
// depending on how closely we are tracking outstanding packets.
//
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) pNdisPacket)
#define szEPVCASSOC_EXTLINK_INDICATED_PKT_FORMAT " indicated pkt 0x%p\n"
//
// If ARPDBG_REF_EVERY_PKT
// We add an "external" link for EVERY packet. We'll later remove this
// reference when the send completes for this packet.
// else
// Only a transition from zero to non-zero outstanding sends, we
// add an "external" link. We'll later remove this link when the
// transition from non-zero to zero happens.
//
#if RM_EXTRA_CHECKING
RM_DECLARE_STACK_RECORD(sr)
epvcLinkToExternal (
pHdr, // pHdr
0x92036e12, // LUID
OUR_EXTERNAL_ENTITY, // External entity
EPVC_ASSOC_EXTLINK_INDICATED_PKT, // AssocID
szEPVCASSOC_EXTLINK_INDICATED_PKT_FORMAT ,
&sr
);
#else // !RM_EXTRA_CHECKING
RmLinkToExternalFast(pHdr);
#endif // !RM_EXTRA_CHECKING
#undef OUR_EXTERNAL_ENTITY
#undef szEPVCASSOC_EXTLINK_INDICATED_PKT_FORMAT
#if RM_EXTRA_CHECKING
RM_ASSERT_CLEAR(&sr);
#endif
}
VOID
epvcDerefRecvPkt (
PNDIS_PACKET pNdisPacket,
PRM_OBJECT_HEADER pHdr
)
{
// The following macros are just so that we can make
// the proper debug association
// depending on how closely we are tracking outstanding send packets.
//
#if RM_EXTRA_CHECKING
RM_DECLARE_STACK_RECORD(sr)
epvcUnlinkFromExternal(
pHdr, // pHdr
0x110ad55b, // LUID
(UINT_PTR)pNdisPacket, // External entity
EPVC_ASSOC_EXTLINK_INDICATED_PKT, // AssocID
&sr
);
#else // !RM_EXTRA_CHECKING
RmUnlinkFromExternalFast (pHdr);
#endif // !RM_EXTRA_CHECKING
#if RM_EXTRA_CHECKING
RM_ASSERT_CLEAR(&sr);
#endif
}
VOID
epvcDerefSendPkt (
PNDIS_PACKET pNdisPacket,
PRM_OBJECT_HEADER pHdr
)
{
// The following macros are just so that we can make
// the proper debug association
// depending on how closely we are tracking outstanding send packets.
//
#if RM_EXTRA_CHECKING
RM_DECLARE_STACK_RECORD(sr)
epvcUnlinkFromExternal(
pHdr, // pHdr
0xf43e0a10, // LUID
(UINT_PTR)pNdisPacket, // External entity
EPVC_ASSOC_EXTLINK_PKT_TO_SEND, // AssocID
&sr
);
#else // !RM_EXTRA_CHECKING
RmUnlinkFromExternalFast (pHdr);
#endif // !RM_EXTRA_CHECKING
#if RM_EXTRA_CHECKING
RM_ASSERT_CLEAR(&sr);
#endif
}
VOID
epvcRefSendPkt(
PNDIS_PACKET pNdisPacket,
PRM_OBJECT_HEADER pHdr // either an adapter or a miniport
)
{
// The following macros are just so that we can make
// the proper debug association
// depending on how closely we are tracking outstanding send packets.
//
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) pNdisPacket)
#define szEPVCASSOC_EXTLINK_DEST_TO_PKT_FORMAT " send pkt 0x%p\n"
#if RM_EXTRA_CHECKING
RM_DECLARE_STACK_RECORD(sr)
epvcLinkToExternal (
pHdr, // pHdr
0xabd17475, // LUID
OUR_EXTERNAL_ENTITY, // External entity
EPVC_ASSOC_EXTLINK_PKT_TO_SEND, // AssocID
szEPVCASSOC_EXTLINK_DEST_TO_PKT_FORMAT ,
&sr
);
#else // !RM_EXTRA_CHECKING
RmLinkToExternalFast(pHdr);
#endif // !RM_EXTRA_CHECKING
#undef OUR_EXTERNAL_ENTITY
#undef szEPVCASSOC_EXTLINK_DEST_TO_PKT_FORMAT
#if RM_EXTRA_CHECKING
RM_ASSERT_CLEAR(&sr);
#endif
}
VOID
epvcExtractPktInfo (
PEPVC_I_MINIPORT pMiniport,
PNDIS_PACKET pPacket ,
PEPVC_SEND_STRUCT pSendStruct
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
pSendStruct->pOldPacket = pPacket;
pSendStruct->pMiniport = pMiniport;
epvcSetSendPktStats();
}
NDIS_STATUS
epvcSendRoutine(
IN PEPVC_I_MINIPORT pMiniport,
IN PNDIS_PACKET Packet,
PRM_STACK_RECORD pSR
)
/*++
Routine Description:
This routine does all the hard work.
It responds to arps if necessary..
It removes Ethernet Headers if necessary
It allocates a new packet if necessary
It sends the new packet on the wire
Arguments:
pMiniport - Miniport in question
Packet - Packet to be sent
Return Value:
Returns Pending, otherwise expects the calling
routine to complete the packet
--*/
{
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PNDIS_PACKET pNewPkt = NULL;
EPVC_SEND_STRUCT SendStruct;
TRACE (TL_T, TM_Send, ("==>epvcSendRoutine") );
EPVC_ZEROSTRUCT (&SendStruct);
do
{
epvcExtractPktInfo (pMiniport, Packet, &SendStruct );
//
// if we are doing IP encapsulation, then respond
// to the Arp
//
if (pMiniport->fDoIpEncapsulation == TRUE)
{
//
// We need to do some special processing for this packet
//
SendStruct.fIsThisAnArp = \
epvcCheckAndReturnArps (pMiniport,
Packet ,
&SendStruct,
pSR);
if (SendStruct.fIsThisAnArp == TRUE )
{
Status = NDIS_STATUS_SUCCESS;
break ; // Arps are not sent to the atm driver
}
if (SendStruct.fNotIPv4Pkt == TRUE)
{
// This is not an IPv4 packet. Fail the send.
Status = NDIS_STATUS_FAILURE;
break;
}
}
//
// Allocate a new packet to be sent
//
epvcGetSendPkt(pMiniport,
Packet,
&SendStruct,
pSR);
if (SendStruct.pNewPacket == NULL)
{
ASSERTAndBreak (SendStruct.pNewPacket != NULL);
}
//
// SendStruct.pNewPacket is guaranteed to have the NdisBuffers Set up
//
// Remove Ethernet Header - if necessary
//
Status = epvcRemoveEthernetHeader (&SendStruct, pSR);
if (Status != NDIS_STATUS_SUCCESS)
{
ASSERTAndBreak (Status == NDIS_STATUS_SUCCESS)
}
//
// Add Ethernet Padding - if necessary
//
Status = epvcAddEthernetTail (&SendStruct, pSR);
if (Status != NDIS_STATUS_SUCCESS)
{
ASSERTAndBreak (Status == NDIS_STATUS_SUCCESS)
}
//
// Add Ethernet Pad 0x00 0x00 to head of packet - if necessary
//
Status = epvcAddEthernetPad (&SendStruct, pSR);
if (Status != NDIS_STATUS_SUCCESS)
{
ASSERTAndBreak (Status == NDIS_STATUS_SUCCESS)
}
//
// Add LLC Encapsulation - if necessary
//
Status = epvcAddLLCEncapsulation (pMiniport , Packet, SendStruct.pNewPacket, pSR);
if (Status != NDIS_STATUS_SUCCESS)
{
ASSERTAndBreak (Status == NDIS_STATUS_SUCCESS)
}
//
// set the context information for the send complete
//
epvcSetPacketContext (&SendStruct, pSR);
//
// Only Send if successful
//
epvcDumpPkt (SendStruct.pNewPacket);
Status = epvcAdapterSend(pMiniport,
SendStruct.pNewPacket,
pSR);
} while (FALSE);
if (Status != NDIS_STATUS_PENDING && // We had a failure
SendStruct.pNewPacket != NULL ) // but we were able to get a packet
{
epvcFreeSendPkt (pMiniport, &SendStruct);
}
TRACE (TL_T, TM_Send, ("<==epvcSendRoutine") );
return Status;
}
VOID
EpvcSendPackets(
IN NDIS_HANDLE MiniportAdapterContext,
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets
)
/*++
Routine Description:
Send Packet Array handler. Either this or our SendPacket handler is called
based on which one is enabled in our Miniport Characteristics.
Arguments:
MiniportAdapterContext Pointer to our adapter
PacketArray Set of packets to send
NumberOfPackets Self-explanatory
Return Value:
None
--*/
{
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT)MiniportAdapterContext;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
UINT i;
RM_DECLARE_STACK_RECORD (SR);
DBGMARK(0xdaab68c3);
TRACE (TL_T, TM_Send, ("==>EpvcSendPackets pMiniport %p, pPktArray %p, Num %x",
pMiniport, PacketArray, NumberOfPackets));
for (i = 0; i < NumberOfPackets; i++)
{
PEPVC_PKT_CONTEXT Rsvd;
PNDIS_PACKET Packet = NULL;
Packet = PacketArray[i];
epvcValidatePacket (Packet);
Status= epvcSendRoutine (pMiniport, Packet, &SR);
if (Status != NDIS_STATUS_PENDING)
{
epvcMSendComplete(pMiniport, Packet , Status);
}
}
TRACE (TL_T, TM_Send, ("<==EpvcSendPackets "));
RM_ASSERT_CLEAR(&SR);
return;
}
VOID
epvcFreeSendPkt(
PEPVC_I_MINIPORT pMiniport,
IN PEPVC_SEND_STRUCT pSendStruct
)
/*++
Routine Description:
Pops the packet stack if stacks were used or free the new packet after
copying the per packet info
Arguments:
pMiniport - which the packet was sent to
pSentPkt - The packet that is being sent.
ppPkt - the new packet that was allocated or the old one if a stack was available
--*/
{
ENTER ("epvcFreeSendPkt", 0xff3ce0fd)
PNDIS_PACKET pOldPkt = pSendStruct->pOldPacket;
PNDIS_PACKET pNewPkt = pSendStruct->pNewPacket;
TRACE (TL_T, TM_Send, ("==>epvcFreeSendPkt pNewPkt %x, pPOldPkt ",pNewPkt, pOldPkt));
//
// Remove the ethernet padding - if necessary
//
epvcRemoveEthernetPad (pMiniport, pNewPkt);
//
// Remove the Ethernet Tail- if necessary
//
epvcRemoveEthernetTail(pMiniport, pNewPkt, &pSendStruct->Context);
//
// If the two packets are the same, then we used Packet Stacks
//
if (pNewPkt != NULL && pSendStruct->fUsingStacks== FALSE)
{
NdisIMCopySendCompletePerPacketInfo (pOldPkt, pNewPkt);
epvcFreePacket(pNewPkt,&pMiniport->PktPool.Send);
pNewPkt = pSendStruct->pNewPacket = NULL;
}
TRACE (TL_T, TM_Send, ("<==epvcFreeSendPkt pNewPkt %x, pPOldPkt ",pNewPkt, pOldPkt));
EXIT()
return;
}
VOID
epvcGetSendPkt (
IN PEPVC_I_MINIPORT pMiniport,
IN PNDIS_PACKET pSentPkt,
OUT PEPVC_SEND_STRUCT pSendStruct,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Allocates an NdisPkt or pushes a Pkt Stack to get a valid NdisPkt that
can be sent to the adapter below.
Arguments:
pMiniport - which the packet was sent to
pSentPkt - The packet that is being sent.
ppPkt - the new packet that was allocated or the old one if a stack was available
--*/
{
ENTER ("epvcGetSendPkt", 0x5734054f)
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PNDIS_PACKET pNewPkt = NULL;
BOOLEAN Remaining = FALSE;
PVOID MediaSpecificInfo = NULL;
UINT MediaSpecificInfoSize = 0;
TRACE (TL_T, TM_Send, ("==>epvcGetSendPkt pSentPkt %x",pSentPkt));
do
{
#if PKT_STACKS
//
// Packet stacks: Check if we can use the same packet for sending down.
//
pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
if (Remaining)
{
//
// We can reuse "Packet".
//
// NOTE: if we needed to keep per-packet information in packets
// sent down, we can use pStack->IMReserved[].
//
pNewPkt = pSentPkt;
pSendStruct->pPktStack = pStack;
pSendStruct->fUsingStacks = TRUE;
break;
}
#endif
pSendStruct->fUsingStacks = FALSE;
epvcAllocatePacket(&Status,
&pNewPkt,
&pMiniport->PktPool.Send);
if (Status == NDIS_STATUS_SUCCESS)
{
PNDIS_PACKET_EXTENSION Old, New;
PEPVC_PKT_CONTEXT Rsvd = NULL;
Rsvd = (PEPVC_PKT_CONTEXT)(pNewPkt->ProtocolReserved);
Rsvd->pOriginalPacket = pSentPkt;
pNewPkt->Private.Flags = NdisGetPacketFlags(pSentPkt);
pNewPkt->Private.Head = pSentPkt->Private.Head;
pNewPkt->Private.Tail = pSentPkt->Private.Tail;
//
// Copy the OOB Offset from the original packet to the new
// packet.
//
NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(pNewPkt),
NDIS_OOB_DATA_FROM_PACKET(pSentPkt),
sizeof(NDIS_PACKET_OOB_DATA));
//
// Copy relevant parts of the per packet info into the new packet
//
NdisIMCopySendPerPacketInfo(pNewPkt, pSentPkt);
//
// Copy the Media specific information
//
NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(pSentPkt,
&MediaSpecificInfo,
&MediaSpecificInfoSize);
if (MediaSpecificInfo || MediaSpecificInfoSize)
{
NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(pNewPkt,
MediaSpecificInfo,
MediaSpecificInfoSize);
}
}
else
{
pNewPkt = NULL;
}
} while (FALSE);
pSendStruct->pNewPacket = pNewPkt;
TRACE (TL_T, TM_Send, ("<==epvcGetSendPkt pSentPkt %p ppNewPkt %p",pSentPkt, pSendStruct->pNewPacket ));
EXIT()
return;
}
NDIS_STATUS
epvcAdapterSend(
IN PEPVC_I_MINIPORT pMiniport,
IN PNDIS_PACKET pPkt,
PRM_STACK_RECORD pSR
)
{
BOOLEAN fDoSend = FALSE;
PEPVC_ADAPTER pAdapter = pMiniport->pAdapter;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
ENTER("epvcAdapterSend", 0x5b014909)
TRACE (TL_T, TM_Send, (" ==>epvcAdapterSend" ) )
do
{
//
// Check to see if we have a valid Send Case
//
LOCKOBJ (pMiniport, pSR);
fDoSend = MiniportTestFlag (pMiniport, fMP_MakeCallSucceeded);
if (fDoSend == FALSE)
{
TRACE (TL_V, TM_Send,("Send - MakeCall Not Succeeded"));
}
//
// Add an association while holding the lock
//
if (fDoSend == TRUE)
{
epvcRefSendPkt(pPkt, &pMiniport->Hdr);
}
UNLOCKOBJ (pMiniport, pSR);
if (fDoSend == TRUE)
{
epvcCoSendPackets(pMiniport->vc.VcHandle,
&pPkt,
1
);
Status = NDIS_STATUS_PENDING;
}
else
{
Status = NDIS_STATUS_FAILURE;
}
} while (FALSE);
TRACE (TL_T, TM_Send, (" <==epvcAdapterSend fDoSend %x, Status %x", fDoSend, Status ) )
return Status;
}
VOID
epvcFormulateArpResponse (
IN PEPVC_I_MINIPORT pMiniport,
IN PEPVC_ARP_CONTEXT pArpContext,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
This allocates an Arp Packet, looks at the Arp Request, formulates
a response and sends it up back to the protocol
Arguments:
pMiniport - which the packet was sent to
pArpContext - Contains all the information relating to the Arp.
the Context Is Allocated on the stack
Return:
--*/
{
ENTER("epvcFormulateArpResponse", 0x7a763fce)
PEPVC_ARP_PACKET pResponse = NULL;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PTASK_ARP pTask = NULL;
TRACE (TL_T, TM_Send, ("==>epvcFormulateArpResponse pMiniport %x, pArpContext %x",
pMiniport, pArpContext))
do
{
//
// Allocate a buffer from a lookaside list
//
Status = epvcAllocateTask(
&pMiniport->Hdr, // pParentObject,
epvcTaskRespondToArp, // pfnHandler,
0, // Timeout,
"Task: Arp Response", // szDescription
&(PRM_TASK)pTask,
pSR
);
if (FAIL(Status))
{
pTask = NULL;
break;
}
//
// Set up Arp Response
//
pResponse = &pTask->Pkt;
EPVC_ZEROSTRUCT (pResponse);
{
//
// Construct the Ethernet Header
//
PEPVC_ETH_HEADER pRespHeader = &pResponse->Header;
PEPVC_ETH_HEADER pSrcHeader = (PEPVC_ETH_HEADER)pArpContext->pEthHeader;
ASSERT (pSrcHeader != NULL);
ASSERT (pRespHeader != NULL);
//
// set up the Eth header
//
NdisMoveMemory (&pRespHeader->eh_daddr,
&pSrcHeader->eh_saddr,
ARP_802_ADDR_LENGTH ) ;
NdisMoveMemory ( &pRespHeader->eh_saddr,
&pMiniport->info.MacAddressDummy,
ARP_802_ADDR_LENGTH );
pRespHeader->eh_type = pSrcHeader->eh_type; // copy 08 06 over
}
{
//
// Construct the Arp Response
//
PEPVC_ARP_BODY pRespBody = &pResponse->Body;
PEPVC_ARP_BODY pSrcBody = pArpContext ->pBody;
ASSERT (pRespBody != NULL);
ASSERT (pSrcBody != NULL);
pRespBody->hw = pSrcBody->hw; // Hardware address space. = 00 01
pRespBody->pro = pSrcBody->pro; // Protocol address space. = 08 00
pRespBody->hlen = ARP_802_ADDR_LENGTH; // 6
pRespBody->plen = sizeof (IP_ADDR); // 4
pRespBody->opcode = net_short(ARP_RESPONSE); // Opcode.
pRespBody->SenderHwAddr= pMiniport->info.MacAddressDummy; // Source HW address.
pRespBody->SenderIpAddr = pSrcBody->DestIPAddr ; // Source protocol address.
pRespBody->DestHwAddr = pSrcBody->SenderHwAddr; // Destination HW address.
pRespBody->DestIPAddr = pSrcBody->SenderIpAddr; // Destination protocol address.
}
//
// So we have the packet ready for transmission.
//
RmStartTask ((PRM_TASK)pTask, 0 , pSR);
} while (FALSE);
TRACE (TL_T, TM_Send, ("<==epvcFormulateArpResponse "))
}
NDIS_STATUS
epvcTaskRespondToArp(
IN struct _RM_TASK * pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
This function queues a zero timeout timer and indicates a receive
Arguments:
Return:
--*/
{
ENTER("epvcTaskRespondToArp", 0xd05c4942)
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT ) RM_PARENT_OBJECT(pTask);
PTASK_ARP pTaskArp = (PTASK_ARP) pTask;
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER)pMiniport->Hdr.pParentObject;
enum
{
Stage_Start =0, // default
Stage_DoAllocations,
Stage_QueuedTimer,
Stage_PacketReturned,
Stage_TaskCompleted,
Stage_End
}; // To be used in pTask->Hdr.State to indicate the state of the Task
TRACE ( TL_T, TM_Pt, ("==> epvcTaskRespondToArp %x",pTask->Hdr.State ) );
switch (pTask->Hdr.State)
{
case Stage_Start:
{
LOCKOBJ (pMiniport, pSR);
if (epvcIsThisTaskPrimary ( pTask, &(PRM_TASK)(pMiniport->arps.pTask)) == FALSE)
{
PRM_TASK pOtherTask = (PRM_TASK)(pMiniport->arps.pTask);
RmTmpReferenceObject (&pOtherTask->Hdr, pSR);
//
// Set The state so we restart this code after main task completes
//
pTask->Hdr.State = Stage_Start;
UNLOCKOBJ(pMiniport, pSR);
RmPendTaskOnOtherTask (pTask, 0, pOtherTask, pSR);
RmTmpDereferenceObject(&pOtherTask->Hdr,pSR);
Status = NDIS_STATUS_PENDING;
break;
}
//
// We are the primary task
//
//
// Check to see if the miniport is still active.
// If it is halting, then we don't need to do any work
//
if (MiniportTestFlag(pMiniport, fMP_MiniportInitialized) == FALSE)
{
//
// Our work had been done. So break out and complete the task
//
Status = NDIS_STATUS_SUCCESS;
pTask->Hdr.State = Stage_TaskCompleted;
UNLOCKOBJ(pMiniport, pSR);
break;
}
UNLOCKOBJ(pMiniport, pSR);
pTask->Hdr.State = Stage_DoAllocations;
FALL_THROUGH
}
case Stage_DoAllocations:
{
PNDIS_BUFFER pBuffer = NULL;
TRACE (TL_V, TM_Send, ("epvcTaskRespondToArp Stage_DoAllocations Task %p", pTask) );
//
// Allocate An NDis Buffer
//
epvcAllocateBuffer(&Status,
&pBuffer,
NULL, // Pool Handle
(PVOID)&pTaskArp->Pkt,
sizeof(pTaskArp->Pkt) ); //Length
ASSERT (sizeof(pTaskArp->Pkt) == 0x2a);
if (FAIL(Status) == TRUE)
{
pBuffer = NULL;
pTask->Hdr.State = Stage_TaskCompleted;
ASSERTAndBreak (!FAIL(Status));
break;
}
//
// Allocate An Ndis Packet
//
epvcAllocatePacket (&Status,
&pTaskArp->pNdisPacket,
&pMiniport->PktPool.Recv);
if (FAIL(Status) == TRUE)
{
pTask->Hdr.State = Stage_TaskCompleted;
pTaskArp->pNdisPacket = NULL;
//
// Undo allocations
//
epvcFreeBuffer (pBuffer);
ASSERTAndBreak( !FAIL(Status) );
}
//
// Set up the Ndis Buffer within the NdisPacket
//
{
PNDIS_PACKET_PRIVATE pPktPriv = &pTaskArp->pNdisPacket->Private;
pPktPriv->Head = pBuffer;
pPktPriv->Tail = pBuffer;
pBuffer->Next = NULL;
}
//
// Set up the Arp response
//
//
// Queue the timer
//
NdisMInitializeTimer ( &pTaskArp->Timer,
pMiniport->ndis.MiniportAdapterHandle,
epvcArpTimer,
pTaskArp );
pTask->Hdr.State = Stage_QueuedTimer;
//
// Now prepare to be called back througha timer to do the
// receive indication
//
RmSuspendTask(pTask, 0,pSR);
Status = NDIS_STATUS_PENDING;
NdisMSetTimer (&pTaskArp->Timer, 0); // Zero timeout
break;
}
case Stage_QueuedTimer:
{
TRACE (TL_V, TM_Send, ("epvcTaskRespondToArp Stage_QueuedTimer Task %p", pTask) );
//
// The miniport could have been halted during the timer
//
if (MiniportTestFlag (pMiniport, fMP_MiniportInitialized) == FALSE)
{
pTask->Hdr.State = Stage_TaskCompleted;
ASSERTAndBreak(MiniportTestFlag (pMiniport, fMP_MiniportInitialized) == TRUE);
}
NDIS_SET_PACKET_HEADER_SIZE(pTaskArp->pNdisPacket ,
sizeof (pMiniport->RcvEnetHeader)) ;
NDIS_SET_PACKET_STATUS (pTaskArp->pNdisPacket, NDIS_STATUS_RESOURCES);
pTask->Hdr.State = Stage_PacketReturned;
epvcMIndicateReceivePacket (pMiniport,
&pTaskArp->pNdisPacket,
1 );
FALL_THROUGH
}
case Stage_PacketReturned:
{
pTask->Hdr.State = Stage_TaskCompleted;
Status = NDIS_STATUS_SUCCESS;
break;
}
case Stage_TaskCompleted:
case Stage_End :
{
Status = NDIS_STATUS_SUCCESS;
break;
}
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
}
if (pTask->Hdr.State == Stage_TaskCompleted)
{
//
// Free the packet
//
pTask->Hdr.State = Stage_End;
if (pTaskArp->pNdisPacket != NULL)
{
//
// Free the buffer
//
PNDIS_PACKET_PRIVATE pPrivate = & pTaskArp->pNdisPacket->Private;
if (pPrivate -> Head != NULL)
{
epvcFreeBuffer (pPrivate->Head );
pPrivate->Head = pPrivate->Tail = NULL;
}
//
// free the arp packet
//
epvcFreePacket (pTaskArp->pNdisPacket , &pMiniport->PktPool.Recv);
pTaskArp->pNdisPacket = NULL;
}
LOCKOBJ (pMiniport, pSR);
epvcClearPrimaryTask (&(PRM_TASK)(pMiniport->arps.pTask));
UNLOCKOBJ (pMiniport, pSR);
Status = NDIS_STATUS_SUCCESS;
}
TRACE ( TL_T, TM_Pt, ("<== epvcTaskRespondToArp %x",Status) );
return Status;
}
VOID
epvcArpTimer(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3
)
/*++
Routine Description:
Resume the epvcTaskRespondToArp Task
Arguments:
Return:
--*/
{
ENTER ("epvcArpTimer",0xf2adae0e)
PRM_TASK pTask = (PRM_TASK) FunctionContext;
RM_DECLARE_STACK_RECORD (SR);
RmResumeTask (pTask,0,&SR);
EXIT()
}
BOOLEAN
epvcCheckAndReturnArps (
IN PEPVC_I_MINIPORT pMiniport,
IN PNDIS_PACKET pPkt,
IN PEPVC_SEND_STRUCT pSendStruct,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Looks at the packet that is being sent. If it is an Arp request,
then it formulates a responses and queues a timer of timeout zero to
return the Arp
Arguments:
pMiniport - which the packet was sent to
pPkt - the packet being sent
Return:
True - if this is an Arp Request.
--*/
{
ENTER("epvcCheckAndReturnArps ", 0xb8e6a3c4)
EPVC_ARP_CONTEXT ArpContext;
TRACE (TL_T, TM_Send, ("==>epvcCheckAndReturnArps "));
EPVC_ZEROSTRUCT (&ArpContext);
do
{
ArpContext.pFirstBuffer = pPkt->Private.Head;
//
// Do some sanity checks
//
if (ArpContext.pFirstBuffer == NULL)
{
break;
}
NdisQueryBufferSafe( ArpContext.pFirstBuffer ,
&(PVOID)ArpContext.pEthHeader,
&ArpContext.BufferLength,
LowPagePriority );
if (ArpContext.pEthHeader == NULL)
{
break;
}
//
// It the is not an ARP request then ignore it --
// during testing only
//
if (ArpContext.pEthHeader->eh_daddr.Byte[0] == 0xff &&
ArpContext.pEthHeader->eh_daddr.Byte[1] == 0xff )
{
pSendStruct->fNonUnicastPacket = TRUE;
}
if (ARP_ETYPE_ARP != net_short(ArpContext.pEthHeader->eh_type))
{
//
// This is not an Arp packet. Is this an IPv4 packet
//
if (IP_PROT_TYPE != net_short(ArpContext.pEthHeader->eh_type))
{
// If this is not an IPv4 packet, then mark it so that it can
// be discarded
pSendStruct->fNotIPv4Pkt = TRUE;
}
break;
}
//
// We'll parse the structure using pre-defined structs
//
ArpContext.pArpPkt = (PEPVC_ARP_PACKET)ArpContext.pEthHeader;
ASSERT (ArpContext.BufferLength >= sizeof (EPVC_ARP_PACKET));
if (ArpContext.BufferLength < sizeof (EPVC_ARP_PACKET))
{
//
// TODO : Add Code to handle this case.
//
break;
}
ArpContext.pBody = (PEPVC_ARP_BODY)&ArpContext.pArpPkt->Body;
TRACE (TL_V, TM_Send, ("Received an ARP %p, Body %x\n", ArpContext.pEthHeader, ArpContext.pBody));
//
// Validate the Opcode, the prot type, hard size, prot size
//
if (ARP_REQUEST != net_short (ArpContext.pBody->opcode ))
{
//
// This is not an Arp request
//
break;
}
if (IP_PROT_TYPE != net_short(ArpContext.pBody->pro) ||
ARP_802_ADDR_LENGTH != ArpContext.pBody->hlen ||
sizeof (IP_ADDR) != ArpContext.pBody->plen )
{
//
// these are just sanity checks
//
ASSERT (!"Invalid ARP Packet");
break;
}
//
// We have a valid ArpRequest
//
ArpContext.fIsThisAnArp = TRUE;
//
// If tcp/ip is arping for itself, then do not respond... but return
// TRUE, so that this packet is not sent on the wire
//
if (ArpContext.pArpPkt->Body.SenderIpAddr == ArpContext.pArpPkt->Body.DestIPAddr)
{
break;
}
//
// Formulate and indicate an Arp Response
//
epvcFormulateArpResponse (pMiniport, &ArpContext, pSR);
} while (FALSE);
EXIT()
return ArpContext.fIsThisAnArp ;
TRACE (TL_T, TM_Send, ("<==epvcCheckAndReturnArps "));
}
NDIS_STATUS
epvcRemoveEthernetHeader(
PEPVC_SEND_STRUCT pSendStruct,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Expects that the new packet is already set up with
the Ndis Bufferz
Arguments:
pSendStruct - Contains all the arguments that are needed.
Return:
True - if this is an Arp Request.
--*/
{
ENTER ("epvcAddLLCEncapsulation" , 0x3ec589c9)
BOOLEAN fUsedPktStack = pSendStruct->fUsingStacks;
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
PNDIS_PACKET pNewPkt = pSendStruct->pNewPacket;
PEPVC_I_MINIPORT pMiniport = pSendStruct->pMiniport;
TRACE (TL_T, TM_Send, ("==>epvcRemoveEthernetHeader "));
do
{
ULONG BufferLength = 0;
PNDIS_BUFFER pBuffer = NULL;
if (pMiniport->fDoIpEncapsulation == FALSE)
{
NdisStatus = NDIS_STATUS_SUCCESS;
break; // we are done
}
//
// There are three ways we can be given a ether net header
// 1. In a seperate MDL - most often
// 2. As part of a large MDL - We need to adhust the Virtual address
// 3. EthernetHeader is seperated across multiple
// MDLs - not implemented or expected
//
pBuffer = pNewPkt->Private.Head;
BufferLength = NdisBufferLength (pBuffer);
if (BufferLength < sizeof (EPVC_ETH_HEADER) )
{
ASSERTAndBreak (BufferLength >= sizeof (EPVC_ETH_HEADER)) ; // we are done
}
//
// At this point the first buffer is going to be replaced so keep a record of it
//
pSendStruct->Context.Stack.ipv4Send.pOldHeadNdisBuffer = pBuffer;
//
// New we check to see if all we need to do is make the
// Packet->Private.Head point to the next MDL
//
if (BufferLength == sizeof (EPVC_ETH_HEADER))
{
//
// These are error conditions that should not
// be handled in our software
//
ASSERT (pBuffer->Next != NULL); // no tcp header after the Eth header
pNewPkt->Private.Head = pBuffer->Next;
NdisStatus = NDIS_STATUS_SUCCESS;
break ; // we are done
}
if (BufferLength > sizeof (EPVC_ETH_HEADER))
{
//
// Allocate a new NDIS Buffer pointing to start of the IP header w
// within the current Head (pBuffer)
//
PNDIS_BUFFER pNewBuffer = NULL;
PUCHAR pIpHeader = NdisBufferVirtualAddress(pBuffer);
UINT LenRemaining = BufferLength - sizeof (EPVC_ETH_HEADER);
if (pIpHeader == NULL)
{
//
// we did not get the virtual address from the system.
// Start to fail this packet
//
ASSERTAndBreak(pIpHeader != NULL);
}
//
// Now move the Ip Header past the Ethernet Header (where it currently points to)
//
pIpHeader += sizeof (EPVC_ETH_HEADER) ;
//
// Now allocate the new NdisBuffer
//
epvcAllocateBuffer ( &NdisStatus,
&pNewBuffer,
NULL,
pIpHeader,
LenRemaining);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
pNewBuffer = NULL;
ASSERTAndBreak (!"Ndis Buffer Allocation failed");
}
//
// Make the New Buffer the Head of the new packet
//
// We might have to make it the tail if there is
// only one ndis buffer in the packet
//
if (pNewPkt->Private.Head == pNewPkt->Private.Tail)
{
pNewPkt->Private.Tail = pNewBuffer;
}
pNewBuffer->Next= pNewPkt->Private.Head->Next;
pNewPkt->Private.Head = pNewBuffer;
NdisStatus = NDIS_STATUS_SUCCESS;
break ; // we are done
}
} while (FALSE);
TRACE (TL_T, TM_Send, ("<==epvcRemoveEthernetHeader "));
return NdisStatus ;
}
VOID
epvcSetPacketContext (
IN PEPVC_SEND_STRUCT pSendStruct,
PRM_STACK_RECORD pSR
)
/*++
Routine Description:
No allocations, just add a few pointers and exit
Arguments:
pSendStruct - Contains all the arguments that are needed.
Return:
None:
--*/
{
PNDIS_PACKET pPkt = pSendStruct->pNewPacket;
PEPVC_STACK_CONTEXT pStack = NULL;
//
// first point the context to the correct place
// in the new ndis pakcet
//
if (pSendStruct->fUsingStacks == TRUE)
{
pStack = (PEPVC_STACK_CONTEXT)(&pSendStruct->pPktStack->IMReserved[0]);
}
else
{
PEPVC_PKT_CONTEXT pContext = NULL;
pContext = (PEPVC_PKT_CONTEXT )(&pPkt->ProtocolReserved[0]);
pContext->pOriginalPacket = pSendStruct->pOldPacket;
pStack = &pContext->Stack;
}
//
// Update the packet
//
ASSERT (sizeof (pStack) <= (2 *sizeof (PVOID) ));
//
// Now copy the stack portion of the context over
// into the packet
//
*pStack = pSendStruct->Context.Stack;
}
NDIS_STATUS
epvcAddLLCEncapsulation (
PEPVC_I_MINIPORT pMiniport ,
PNDIS_PACKET pOldPkt,
PNDIS_PACKET pNewPkt,
PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Expects that the new packet is already set up with
the Ndis Bufferz
Arguments:
pSendStruct - Contains all the arguments that are needed.
Return:
True - if this is an Arp Request.
--*/
{
ENTER ("epvcAddLLCEncapsulation" , 0x3ec589c9)
BOOLEAN fDoSend = TRUE;
BOOLEAN fUsedPktStack = (pOldPkt == pNewPkt);
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
PNDIS_BUFFER pNewBuffer = NULL;
TRACE (TL_T, TM_Send, ("==>epvcAddLLCEncapsulation "));
do
{
if (pMiniport->fAddLLCHeader == FALSE)
{
break; // we are done
}
//
// Allocate an MDL that points to the LLC Header
//
epvcAllocateBuffer ( &NdisStatus,
&pNewBuffer,
NULL,
pMiniport->pLllcHeader,
pMiniport->LlcHeaderLength);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
pNewBuffer = NULL;
break;
}
//
// Insert the New Buffer as the Head of the new Packet
//
pNewBuffer->Next = pNewPkt->Private.Head;
pNewPkt->Private.Head = pNewBuffer;
pNewPkt->Private.ValidCounts= FALSE;
NdisStatus = NDIS_STATUS_SUCCESS;
} while (FALSE);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
if (pNewBuffer!= NULL)
{
epvcFreeBuffer (pNewBuffer);
pNewBuffer = NULL;
}
}
TRACE (TL_T, TM_Send, ("<==epvcAddLLCEncapsulation "));
return NdisStatus ;
}
NDIS_STATUS
epvcRemoveSendEncapsulation (
PEPVC_I_MINIPORT pMiniport ,
PNDIS_PACKET pNewPkt
)
{
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
epvcRemoveRecvEncapsulation (
PEPVC_I_MINIPORT pMiniport ,
PNDIS_PACKET pNewPkt
)
{
return NDIS_STATUS_SUCCESS;
}
VOID
epvcDumpPkt (
IN PNDIS_PACKET pPkt
)
{
PNDIS_BUFFER pPrevBuffer;
do
{
PNDIS_BUFFER pBuffer = NULL;
if (g_bDumpPackets == FALSE)
{
break;
}
pBuffer = pPkt->Private.Head;
//
// Now iterate through all the buffers
// and print out the packet.
//
TRACE (TL_A, TM_Mp, ("pPkt %p, Head %p, tail %p\n ",
pPkt, pPkt->Private.Head, pPkt->Private.Tail));
//
// As we always expect the first buffer to be present
// I do not check
//
do
{
PVOID pVa = NULL;
ULONG Len = 0;
pPrevBuffer = NULL;
Len = NdisBufferLength (pBuffer);
pVa = NdisBufferVirtualAddress(pBuffer);
pPrevBuffer = pBuffer;
pBuffer = pBuffer->Next;
if (pVa == NULL)
{
continue;
}
DbgPrint ("Mdl %p, Va %p. Len %x\n", pPrevBuffer, pVa,Len);
Dump( (CHAR* )pVa, Len, 0, 1 );
} while (pBuffer != NULL);
} while (FALSE);
}
NDIS_STATUS
epvcMiniportReadConfig(
IN PEPVC_I_MINIPORT pMiniport,
NDIS_HANDLE WrapperConfigurationContext,
PRM_STACK_RECORD pSR
)
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NDIS_HANDLE ConfigurationHandle;
PMP_REG_ENTRY pRegEntry;
UINT i;
UINT value;
PUCHAR pointer;
PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
PUCHAR NetworkAddress;
UINT Length;
// Open the registry for this pMiniport
NdisOpenConfiguration(
&Status,
&ConfigurationHandle,
WrapperConfigurationContext);
if(Status != NDIS_STATUS_SUCCESS)
{
TRACE (TL_I, TM_Mp,("NdisOpenConfiguration failed\n"));
return Status;
}
// read all the registry values
for(i = 0, pRegEntry = NICRegTable; i < NIC_NUM_REG_PARAMS; i++, pRegEntry++)
{
pointer = (PUCHAR) pMiniport + pRegEntry->FieldOffset;
// Get the configuration value for a specific parameter. Under NT the
// parameters are all read in as DWORDs.
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigurationHandle,
&pRegEntry->RegName,
NdisParameterInteger);
// If the parameter was present, then check its value for validity.
if(Status == NDIS_STATUS_SUCCESS)
{
// Check that param value is not too small or too large
if(ReturnedValue->ParameterData.IntegerData < pRegEntry->Min ||
ReturnedValue->ParameterData.IntegerData > pRegEntry->Max)
{
value = pRegEntry->Default;
}
else
{
value = ReturnedValue->ParameterData.IntegerData;
}
TRACE (TL_I, TM_Mp, ("= 0x%x", value));
}
else if(pRegEntry->bRequired)
{
TRACE (TL_I, TM_Mp,(" -- failed"));
ASSERT(FALSE);
Status = NDIS_STATUS_FAILURE;
break;
}
else
{
value = pRegEntry->Default;
TRACE (TL_I, TM_Mp,("= 0x%x (default)", value));
Status = NDIS_STATUS_SUCCESS;
}
// Store the value in the pMiniport structure.
switch(pRegEntry->FieldSize)
{
case 1:
*((PUCHAR) pointer) = (UCHAR) value;
break;
case 2:
*((PUSHORT) pointer) = (USHORT) value;
break;
case 4:
*((PULONG) pointer) = (ULONG) value;
break;
default:
TRACE (TL_I,TM_Mp, ("Bogus field size %d", pRegEntry->FieldSize));
break;
}
}
// Read NetworkAddress registry value
// Use it as the current address if any
// Close the registry
NdisCloseConfiguration(ConfigurationHandle);
TRACE (TL_I, TM_Mp,("vci %d\n", pMiniport->config.vci));
TRACE (TL_I, TM_Mp,("vpi %d\n", pMiniport->config.vpi));
TRACE (TL_I, TM_Mp,("Encap Type %x\n", pMiniport->Encap));
TRACE (TL_T, TM_Mp, ("<-- NICReadRegParameters, Status=%x", Status));
return Status;
}
VOID
epvcInitializeMiniportLookasideLists (
IN PEPVC_I_MINIPORT pMiniport
)
/*++
Routine Description:
Initialize all the lookaside lists in the adapter block
Arguments:
Return Value:
None.
--*/
{
USHORT DefaultDepth = 15;
extern const UINT MaxEthernetFrameSize ;
TRACE( TL_T, TM_Mp, ( "==> nicInitializeMiniportLookasideLists pMiniport %x ", pMiniport ) );
switch (pMiniport->Encap)
{
case IPV4_ENCAP_TYPE:
case IPV4_LLC_SNAP_ENCAP_TYPE:
{
epvcInitializeLookasideList ( &pMiniport->arps.LookasideList,
sizeof (EPVC_TASK),
TAG_TASK,
DefaultDepth );
epvcInitializeLookasideList ( &pMiniport->rcv.LookasideList,
sizeof (EPVC_IP_RCV_BUFFER),
TAG_RCV ,
DefaultDepth );
break;
}
case ETHERNET_ENCAP_TYPE:
case ETHERNET_LLC_SNAP_ENCAP_TYPE:
{
break;
}
default:
{
}
}
TRACE( TL_T, TM_Mp, ( "<== nicInitializeMiniportLookasideLists " ) );
}
VOID
epvcDeleteMiniportLookasideLists (
IN PEPVC_I_MINIPORT pMiniport
)
/*++
Routine Description:
Delete all the lookaside lists in the adapter block
Arguments:
Return Value:
None.
--*/
{
TRACE( TL_T, TM_Mp, ( "== epvcDeleteMiniportLookasideLists pMiniport %x ", pMiniport) );
//
// Deletes the lookaside lists if they have been allocated
//
epvcDeleteLookasideList (&pMiniport->rcv.LookasideList);
epvcDeleteLookasideList (&pMiniport->arps.LookasideList);
}
NDIS_STATUS
epvcInitializeMiniportPacketPools (
IN PEPVC_I_MINIPORT pMiniport
)
/*++
Routine Description:
Initializr all the packet pools in the miniport
Arguments:
Return Value:
None.
--*/
{
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
TRACE( TL_T, TM_Mp, ( "==> epvcInitializeMiniportPacketPools pMiniport %x ", pMiniport ) );
do
{
epvcAllocatePacketPool (&Status,
&pMiniport->PktPool.Send,
MIN_PACKET_POOL_SIZE,
MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
sizeof(EPVC_PKT_CONTEXT));
if (Status != NDIS_STATUS_SUCCESS)
{
EPVC_ZEROSTRUCT (&pMiniport->PktPool.Send);
ASSERT (Status == NDIS_STATUS_SUCCESS);
break;
}
epvcAllocatePacketPool (&Status,
&pMiniport->PktPool.Recv,
MIN_PACKET_POOL_SIZE,
MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
PROTOCOL_RESERVED_SIZE_IN_PACKET);
if (Status != NDIS_STATUS_SUCCESS)
{
EPVC_ZEROSTRUCT (&pMiniport->PktPool.Recv);
ASSERT (Status == NDIS_STATUS_SUCCESS);
break;
}
} while ( FALSE);
if (Status != NDIS_STATUS_SUCCESS)
{
epvcDeleteMiniportPacketPools (pMiniport);
}
TRACE( TL_T, TM_Mp, ( "<== epvcInitializeMiniportPacketPools Status %x ", Status ) );
return Status;
}
VOID
epvcDeleteMiniportPacketPools (
IN PEPVC_I_MINIPORT pMiniport
)
/*++
Routine Description:
Delete all the packet pools in the miniport block
Arguments:
Return Value:
None.
--*/
{
TRACE( TL_T, TM_Mp, ( "== epvcDeleteMiniportPacketPools pMiniport %x ", pMiniport ) );
//
// Freeing packet pools
//
if (pMiniport->PktPool.Recv.Handle != NULL)
{
epvcFreePacketPool (&pMiniport->PktPool.Recv);
}
if (pMiniport->PktPool.Send.Handle != NULL)
{
epvcFreePacketPool (&pMiniport->PktPool.Send);
}
}
VOID
epvcInitializeMiniportParameters(
PEPVC_I_MINIPORT pMiniport
)
{
//ipv4 - 0
//ipv4 with llc header = 1
//Ethernet - 2
//Ethernet with llc header- 3
//
// Defaults for all flags are FALSE
//
pMiniport->fDoIpEncapsulation = FALSE;
pMiniport->fAddLLCHeader = FALSE;
switch (pMiniport->Encap )
{
case IPV4_ENCAP_TYPE:
{
pMiniport->fDoIpEncapsulation = TRUE;
pMiniport->MinAcceptablePkt =sizeof (IPHeader) ;
pMiniport->MaxAcceptablePkt = EPVC_MAX_FRAME_SIZE -EPVC_ETH_HEADERSIZE ;
break;
}
case IPV4_LLC_SNAP_ENCAP_TYPE:
{
pMiniport->fAddLLCHeader = TRUE;
pMiniport->fDoIpEncapsulation = TRUE;
pMiniport->pLllcHeader = &LLCSnapIpv4[0];
pMiniport->LlcHeaderLength = sizeof(LLCSnapIpv4);
pMiniport->MinAcceptablePkt = sizeof (IPHeader) + sizeof(LLCSnapIpv4);
pMiniport->MaxAcceptablePkt = EPVC_MAX_FRAME_SIZE + sizeof(LLCSnapIpv4)-EPVC_ETH_HEADERSIZE ;
break;
}
case ETHERNET_LLC_SNAP_ENCAP_TYPE:
{
pMiniport->fAddLLCHeader = TRUE;
pMiniport->pLllcHeader = &LLCSnapEthernet[0];
pMiniport->LlcHeaderLength = sizeof(LLCSnapEthernet);
pMiniport->MinAcceptablePkt = MIN_ETHERNET_SIZE + sizeof(LLCSnapEthernet);
pMiniport->MaxAcceptablePkt = EPVC_MAX_FRAME_SIZE +sizeof(LLCSnapEthernet);
break;
}
case ETHERNET_ENCAP_TYPE:
{
pMiniport->MinAcceptablePkt = MIN_ETHERNET_SIZE;
pMiniport->MaxAcceptablePkt = EPVC_MAX_FRAME_SIZE + EPVC_ETH_ENCAP_SIZE;
break;
}
default:
{
ASSERT (!"Not supported - defaulting to Ethernet Encapsulation");
}
}
}
NDIS_STATUS
epvcTaskHaltMiniport(
IN struct _RM_TASK * pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Task handler for opening address families on an underlying adapters.
The number of address families instantiated is determined by the
configuration read in the registry
Arguments:
UserParam for (Code == RM_TASKOP_START) : UnbindContext
--*/
{
ENTER("epvcTaskHaltMiniport", 0xaac34d81)
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT ) RM_PARENT_OBJECT(pTask);
PEPVC_ADAPTER pAdapter = pMiniport->pAdapter;
PTASK_HALT pTaskHalt = (PTASK_HALT)pTask;
BOOLEAN fTaskCompleted = FALSE;
ULONG State;
enum
{
Stage_Start =0, // default
Stage_DeleteVc,
Stage_CloseAfComplete,
Stage_TaskCompleted,
Stage_End
}; // To be used in pTask->Hdr.State to indicate the state of the Task
TRACE(TL_T, TM_Mp, ("==>epvcTaskHaltMiniport State %x", pTask->Hdr.State));
State = pTask->Hdr.State;
switch (pTask->Hdr.State)
{
case Stage_Start:
{
TRACE (TL_V, TM_Mp, (" Task Halt miniport Stage_Start"));
//
// Check to see if the miniport has already halting.
// If so exit
//
LOCKOBJ (pMiniport, pSR );
if (epvcIsThisTaskPrimary ( pTask, &(PRM_TASK)(pMiniport->pnp.pTaskHalt)) == FALSE)
{
PRM_TASK pOtherTask = (PRM_TASK)(pMiniport->pnp.pTaskHalt);
RmTmpReferenceObject (&pOtherTask->Hdr, pSR);
//
// Set The state so we restart this code after main task completes
//
pTask->Hdr.State = Stage_Start;
UNLOCKOBJ(pMiniport, pSR);
RmPendTaskOnOtherTask (pTask, 0, pOtherTask, pSR);
RmTmpDereferenceObject(&pOtherTask->Hdr,pSR);
Status = NDIS_STATUS_PENDING;
break;
}
// We are the primary task and we have the lock
//
ASSERT (pMiniport->pnp.pTaskHalt == pTaskHalt);
//
// Lets close the Call and Delete the Vc
//
UNLOCKOBJ (pMiniport, pSR);
if (MiniportTestFlag (pMiniport, fMP_MakeCallSucceeded) == TRUE)
{
PRM_TASK pVcTask = NULL;
//
// We need to start a task to complete the Close Call And DeleteVC
//
Status = epvcAllocateTask(
&pMiniport->Hdr, // pParentObject,
epvcTaskVcTeardown, // pfnHandler,
0, // Timeout,
"Task: TearDown Vc", // szDescription
&pVcTask ,
pSR
);
if (FAIL(Status))
{
fTaskCompleted = TRUE;
pVcTask = NULL;
ASSERT (Status == NDIS_STATUS_SUCCESS);
break;
}
//
// Now we will pend the halt on the completion of the delete VC
// task
//
pTask->Hdr.State = Stage_DeleteVc;
RmPendTaskOnOtherTask(pTask,
0,
pVcTask,
pSR
);
//
// Start the Vc TearDown
//
RmStartTask (pVcTask , 0, pSR);
//
// Exit - We expect to complete this task in another thread
//
Status = NDIS_STATUS_PENDING;
break;
}
else //if (MiniportTestFlag (pMiniport, fMP_MakeCallSucceeded) == TRUE)
{
pTask->Hdr.State = Stage_DeleteVc;
//
// Continue On - the Vc has already been deleted
//
}
}
case Stage_DeleteVc:
{
//
// Now we check to see if the address family is still
// open for this miniport
//
TRACE (TL_V, TM_Mp, (" Task Halt miniport Stage_DeleteVc"));
if (MiniportTestFlag(pMiniport, fMP_AddressFamilyOpened) == TRUE)
{
PRM_TASK pAfTask = NULL;
//
// We need to start a task to complete the Close Call And DeleteVC
//
Status = epvcAllocateTask(
&pMiniport->Hdr, // pParentObject,
epvcTaskCloseIMiniport, // pfnHandler,
0, // Timeout,
"Task: Close Miniport", // szDescription
&pAfTask ,
pSR
);
if (FAIL(Status))
{
fTaskCompleted = TRUE;
pAfTask = NULL;
ASSERT (Status == NDIS_STATUS_SUCCESS);
break;
}
((PTASK_AF)pAfTask)->Cause = TaskCause_MiniportHalt;
//
// Now we will pend the halt on the completion of the delete VC
// task
//
pTask->Hdr.State = Stage_CloseAfComplete;
RmPendTaskOnOtherTask(pTask,
0,
pAfTask,
pSR
);
//
// Start the Af TearDown
//
RmStartTask (pAfTask , 0, pSR);
//
// Exit - We expect to complete this task in another thread
//
Status = NDIS_STATUS_PENDING;
break;
}
else //if (MiniportTestFlag (pMiniport, fMP_MakeCallSucceeded) == TRUE)
{
pTask->Hdr.State = Stage_CloseAfComplete;
//
// Continue On - the Af has already been deleted
//
}
}
case Stage_CloseAfComplete:
{
//
// Free all miniport resources here .- packet pools etc.
//
TRACE (TL_V, TM_Mp, (" Task Halt miniport Stage_CloseAfComplete"));
//
// Freeing Lookaside lists
//
epvcDeleteMiniportLookasideLists (pMiniport);
//
// Freeing packet pools
//
epvcDeleteMiniportPacketPools(pMiniport);
//
// If the miniport is halting we do not shut down the protocol's adapter
// object
//
fTaskCompleted = TRUE;
Status = NDIS_STATUS_SUCCESS;
break;
}
case Stage_TaskCompleted:
{
ASSERT(0);
break;
}
case Stage_End:
{
TRACE (TL_V, TM_Mp, (" Task Halt miniport Stage_End"));
Status = NDIS_STATUS_SUCCESS;
break;
}
default:
{
ASSERT (pTask->Hdr.State <= Stage_End);
}
} // end of switch
//
// if this thread has completed the postprocessing,
// then signal the event.
//
if (TRUE == fTaskCompleted)
{
BOOLEAN fSetWaitEvent = FALSE;
TRACE (TL_V, TM_Mp, ("Task Halt Miniport - Stage End"));
pTask->Hdr.State = Stage_End;
if (FAIL(Status))
{
ASSERT (0);
}
LOCKOBJ (pMiniport, pSR);
pMiniport->pnp.pTaskHalt = NULL;
if (MiniportTestFlag (pMiniport, fMP_WaitingForHalt)== TRUE)
{
MiniportClearFlag (pMiniport, fMP_WaitingForHalt);
fSetWaitEvent = TRUE;
}
UNLOCKOBJ (pMiniport, pSR);
//
// This first event is for the MiniportHalt handler
// which fired off this task
//
epvcSetEvent (&pTaskHalt->CompleteEvent);
//
// This second event is for the epvcMiniportDoUnbind
// which wants to wait until the Halt is complete ,
// before it shuts off the lower binding to the phy. adapter
//
if (fSetWaitEvent)
{
epvcSetEvent (&pMiniport->pnp.HaltCompleteEvent);
}
Status = NDIS_STATUS_SUCCESS;
}
TRACE(TL_T, TM_Mp, ("<==epvcTaskHaltMiniport Status %x", Status));
EXIT()
RM_ASSERT_NOLOCKS(pSR);
return Status;
}
NDIS_STATUS
epvcAddEthernetTail(
PEPVC_SEND_STRUCT pSendStruct,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Makes sure the ethernet packet is greater than 64 bytes
Arguments:
pSendStruct - Contains all the arguments that are needed.
Return:
Success - if the padding was not needed or the MDL
was successfully appended
--*/
{
ENTER ("epvcAddEthernetTail" , 0x3ec589c9)
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
PNDIS_PACKET pNewPkt = pSendStruct->pNewPacket;
PEPVC_I_MINIPORT pMiniport = pSendStruct->pMiniport;
ULONG PacketLength = 0;
ULONG LengthRemaining = 0;
PNDIS_BUFFER pNewTailBuffer = NULL;
PNDIS_BUFFER pLastBuffer;
TRACE (TL_T, TM_Send, ("==>epvcAddEthernetTail"));
do
{
ULONG BufferLength = 0;
PNDIS_BUFFER pBuffer = NULL;
if (pMiniport->fDoIpEncapsulation == TRUE)
{
NdisStatus = NDIS_STATUS_SUCCESS;
break; // we are done
}
//
// Check the length of the Ethernet packet
//
NdisQueryPacketLength(pNewPkt, &PacketLength);
//
// Is the packet length greater than 64
//
if (PacketLength >= MINIMUM_ETHERNET_LENGTH)
{
NdisStatus= NDIS_STATUS_SUCCESS;
break;
}
//
// Add padding to fill up the minimum Ethernet frame length.
// This is a new buffer that is appended to the original
// NDIS_BUFFER chain.
//
LengthRemaining = MINIMUM_ETHERNET_LENGTH - PacketLength;
NdisAllocateBuffer(&NdisStatus, &pNewTailBuffer, NULL, &gPaddingBytes,LengthRemaining);
if (NdisStatus != NDIS_STATUS_SUCCESS || pNewTailBuffer == NULL)
{
pNewTailBuffer = NULL;
NdisStatus = NDIS_STATUS_RESOURCES;
break;
}
//
// Append the new buffer to the tail of the packet.
//
//
// Locate the last NDIS_BUFFER in the packet. Do it the hard
// way since Packet->Private.Tail is not reliable:
//
pLastBuffer = pNewPkt->Private.Head;
while (pLastBuffer->Next != NULL)
{
pLastBuffer = pLastBuffer->Next;
}
//
// Save a pointer to this last MDL so that we can set its
// Next field back to NULL when we complete this send.
//
pSendStruct->Context.Stack.EthernetSend.pOldLastNdisBuffer = pLastBuffer;
//
// Append the new buffer to the tail of the chain.
//
pLastBuffer->Next = pNewTailBuffer;
pNewTailBuffer->Next = NULL;
//
// Update our packet.
//
pNewPkt->Private.Tail = pNewTailBuffer;
pNewPkt->Private.ValidCounts = FALSE;
NdisStatus = NDIS_STATUS_SUCCESS;
break ; // we are done
} while (FALSE);
if (NdisStatus != NDIS_STATUS_SUCCESS && pNewTailBuffer != NULL)
{
NdisFreeBuffer (pNewTailBuffer);
}
TRACE (TL_T, TM_Send, ("<==epvcAddEthernetTail "));
return NdisStatus ;
}
VOID
epvcRemoveEthernetTail (
IN PEPVC_I_MINIPORT pMiniport,
IN PNDIS_PACKET pPacket,
IN PEPVC_PKT_CONTEXT pContext
)
/*++
Routine Description:
Removes the extra MDL that was added to make
this packet greater than MINIUMUM_ETHERNET_SIZE
Used for Ethernet , Eth +LLC Encapsulations only
Arguments:
pMiniport - Miniport structure
pPacket - Packet allocated by EPVC
pContext - Context of the packet - used to store the original last mdl
Return:
None
--*/
{
PNDIS_BUFFER pOldLastNdisBuffer = NULL;
do
{
//
// Ethernet encapsulation ? If not, then exit
//
if (pMiniport->fDoIpEncapsulation == TRUE)
{
break; // there was no ethernet encapsulation, so exit
}
//
// if there is no old buffer, then we can exit
//
pOldLastNdisBuffer = pContext->Stack.EthernetSend.pOldLastNdisBuffer;
if (pOldLastNdisBuffer == NULL)
{
break;
}
//
// Free the last buffer in the packet (this is the padding
// we added for a runt packet).
//
NdisFreeBuffer(pPacket->Private.Tail);
//
// Set the Next pointer of the original "last buffer" to NULL.
//
pOldLastNdisBuffer->Next = NULL;
} while (FALSE);
}
NDIS_STATUS
epvcAddEthernetPad(
PEPVC_SEND_STRUCT pSendStruct,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Makes sure the ethernet packet w/o LLC header has a pad of
0x00, 0x00
Arguments:
pSendStruct - Contains all the arguments that are needed.
Return:
Success - if the padding was not needed or the MDL
was successfully added
--*/
{
ENTER ("epvcAddEthernetPad" , 0x3ec589c9)
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
PNDIS_PACKET pNewPkt = pSendStruct->pNewPacket;
PEPVC_I_MINIPORT pMiniport = pSendStruct->pMiniport;
PNDIS_BUFFER pPaddingBuffer = NULL;
TRACE (TL_T, TM_Send, ("==>epvcAddEthernetPad"));
do
{
ULONG BufferLength = 0;
PNDIS_BUFFER pBuffer = NULL;
if (pMiniport->Encap != ETHERNET_ENCAP_TYPE)
{
NdisStatus = NDIS_STATUS_SUCCESS;
break; // we are done
}
//
// It is pure Ethernet. We need to precede the packet
// with a 00,00
//
NdisAllocateBuffer(&NdisStatus,
&pPaddingBuffer,
NULL,
&gPaddingBytes,
ETHERNET_PADDING_LENGTH);
if (NdisStatus != NDIS_STATUS_SUCCESS || pPaddingBuffer == NULL)
{
pPaddingBuffer = NULL;
NdisStatus = NDIS_STATUS_RESOURCES;
break;
}
//
// no more allocations - we cannot fail from here
//
NdisStatus = NDIS_STATUS_SUCCESS;
//
// Add the new buffer to the head of the packet
//
NdisChainBufferAtFront(pNewPkt,pPaddingBuffer);
break ; // we are done
} while (FALSE);
if (NdisStatus != NDIS_STATUS_SUCCESS && pPaddingBuffer != NULL)
{
NdisFreeBuffer (pPaddingBuffer);
}
TRACE (TL_T, TM_Send, ("<==epvcAddEthernetPad "));
return NdisStatus ;
}
VOID
epvcRemoveEthernetPad (
IN PEPVC_I_MINIPORT pMiniport,
IN PNDIS_PACKET pPacket
)
/*++
Routine Description:
Removes the padding that was added to the
head of the packet Ethernet Head
Used for Ethernet Encapsulation only
Arguments:
pMiniport - Miniport structure
pPacket - Packet
Return:
None
--*/
{
PNDIS_BUFFER pPaddingBuffer= NULL;
do
{
if (pMiniport->Encap != ETHERNET_ENCAP_TYPE)
{
break; // we are done
}
//
// it is in pure ethernet mode - remove the Padding
//
//
// First - a simple sanity check
//
{
PNDIS_BUFFER pBuffer = pPacket->Private.Head;
ULONG PaddingLength = NdisBufferLength(pBuffer);
if (PaddingLength !=ETHERNET_PADDING_LENGTH)
{
// this is not our MDL
ASSERT (PaddingLength !=ETHERNET_PADDING_LENGTH);
break;
}
}
//
// Free the padding buffer at the front of the Packet
//
NdisUnchainBufferAtFront(pPacket,&pPaddingBuffer );
NdisFreeBuffer (pPaddingBuffer );
} while (FALSE);
}
VOID
epvcCancelDeviceInstance(
IN PEPVC_I_MINIPORT pMiniport ,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
This function cancels an outstanding Device Instance.
If the NDIS call fails. it waits for an event in the miniprot to fire.
After that it goes ahead and DeInitializes the Device Instance
Arguments:
pMiniport - Miniport in question.
Return Value:
Success
--*/
{
ENTER("epvcCancelDeviceInstance", 0x0e42d778)
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
UINT iteration =0;
BOOLEAN bWaitSuccess = FALSE;
BOOLEAN fNeedToInitEvent = FALSE;
do
{
LOCKOBJ (pMiniport, pSR);
// Prepare the event, and mark the structure as being Canceled
epvcResetEvent (&pMiniport->pnp.DeInitEvent);
// Set the flag to mark it as cancelled
MiniportSetFlag (pMiniport, fMP_MiniportCancelInstance);
UNLOCKOBJ (pMiniport, pSR);
// Cancel the device instance
Status = epvcIMCancelInitializeDeviceInstance(pMiniport);
if (Status == NDIS_STATUS_SUCCESS)
{
break;
}
//
// If the Cancel has not Succeeded then we should wait for
// the Initialize to complete
//
{
BOOLEAN bWaitSuccessful;
bWaitSuccessful = epvcWaitEvent (&pMiniport->pnp.DeInitEvent,WAIT_INFINITE);
if (bWaitSuccessful == FALSE)
{
ASSERT (bWaitSuccessful == TRUE);
}
}
//
// If cancel fails. Wait for the miniport to be initialized
//
ASSERT (pMiniport->ndis.MiniportAdapterHandle != NULL);
//
// If cancel fails. Wait for the miniport to be initialized
//
TRACE (TL_N, TM_Mp, ("Call DeInit after Cancel failed %p , ",pMiniport));
epvcIMDeInitializeDeviceInstance (pMiniport);
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
LOCKOBJ(pMiniport, pSR);
MiniportClearFlag (pMiniport, fMP_MiniportCancelInstance);
UNLOCKOBJ (pMiniport, pSR);
return ;
}