1918 lines
51 KiB
C
1918 lines
51 KiB
C
/*++
|
||
|
||
Copyright (c) 1996-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
cmvc.c
|
||
|
||
Abstract:
|
||
|
||
Author:
|
||
Charlie Wickham (charlwi) 13-Sep-1996.
|
||
Rajesh Sundaram (rajeshsu) 01-Aug-1998.
|
||
|
||
Environment:
|
||
|
||
Kernel Mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "psched.h"
|
||
#pragma hdrstop
|
||
|
||
/* External */
|
||
|
||
/* Static */
|
||
|
||
/* Forward */
|
||
|
||
NDIS_STATUS
|
||
RemoveDiffservMapping(
|
||
PGPC_CLIENT_VC Vc
|
||
);
|
||
|
||
NDIS_STATUS
|
||
ProcessDiffservFlow(
|
||
PGPC_CLIENT_VC Vc,
|
||
PCO_CALL_MANAGER_PARAMETERS CallParameters);
|
||
|
||
NDIS_STATUS
|
||
ValidateCallParameters(
|
||
PGPC_CLIENT_VC Vc,
|
||
PCO_CALL_MANAGER_PARAMETERS CallParameters
|
||
);
|
||
|
||
NDIS_STATUS
|
||
AcquireFlowResources(
|
||
PGPC_CLIENT_VC Vc,
|
||
PCO_CALL_MANAGER_PARAMETERS NewCallParams,
|
||
PCO_CALL_MANAGER_PARAMETERS OldCallParams,
|
||
PULONG RemainingBandWidthChanged
|
||
);
|
||
|
||
VOID
|
||
ReturnFlowResources(
|
||
PGPC_CLIENT_VC Vc,
|
||
PULONG RemainingBandWidthChanged
|
||
);
|
||
|
||
VOID
|
||
CancelAcquiredFlowResources(
|
||
PGPC_CLIENT_VC Vc
|
||
);
|
||
|
||
/* End Forward */
|
||
|
||
NDIS_STATUS
|
||
CmCreateVc(PGPC_CLIENT_VC *GpcClientVc,
|
||
PADAPTER Adapter,
|
||
PPS_WAN_LINK WanLink,
|
||
PCO_CALL_PARAMETERS CallParams,
|
||
GPC_HANDLE GpcCfInfoHandle,
|
||
PCF_INFO_QOS CfInfoPtr,
|
||
GPC_CLIENT_HANDLE ClientContext)
|
||
{
|
||
|
||
PGPC_CLIENT_VC Vc;
|
||
|
||
*GpcClientVc = NULL;
|
||
|
||
PsAllocFromLL(&Vc, &GpcClientVcLL, GpcClientVc);
|
||
|
||
if(Vc == NULL)
|
||
{
|
||
return NDIS_STATUS_RESOURCES;
|
||
}
|
||
|
||
InitGpcClientVc(Vc, 0, Adapter);
|
||
SetLLTag(Vc, GpcClientVc);
|
||
|
||
//
|
||
// Allocate space for the instance name for the Vc.
|
||
//
|
||
PsAllocatePool(Vc->InstanceName.Buffer,
|
||
Adapter->WMIInstanceName.Length + VcPrefix.Length + INSTANCE_ID_SIZE,
|
||
PsMiscTag);
|
||
|
||
if(!Vc->InstanceName.Buffer)
|
||
{
|
||
PsFreeToLL(Vc, &GpcClientVcLL, GpcClientVc);
|
||
return NDIS_STATUS_RESOURCES;
|
||
}
|
||
|
||
Vc->CfInfoHandle = GpcCfInfoHandle;
|
||
Vc->CfType = ClientContext;
|
||
Vc->CfInfoQoS = CfInfoPtr;
|
||
Vc->CallParameters = CallParams;
|
||
|
||
PS_LOCK(&Adapter->Lock);
|
||
|
||
if(Adapter->PsMpState == AdapterStateRunning)
|
||
{
|
||
//
|
||
// Insert the Vc in the adapter list
|
||
//
|
||
InsertHeadList(&Adapter->GpcClientVcList, &Vc->Linkage);
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
}
|
||
else
|
||
{
|
||
PsFreePool(Vc->InstanceName.Buffer);
|
||
PsFreeToLL(Vc, &GpcClientVcLL, GpcClientVc);
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
return GPC_STATUS_NOTREADY;
|
||
}
|
||
|
||
|
||
if(WanLink) {
|
||
|
||
Vc->Flags |= GPC_WANLINK_VC;
|
||
|
||
//
|
||
// We need to link the VC to the WanLink. This has to be done because
|
||
// we have to clean up when we get a NDIS_STATUS_WAN_LINE_DOWN
|
||
//
|
||
|
||
Vc->AdapterStats = &WanLink->Stats;
|
||
Vc->WanLink = WanLink;
|
||
Vc->PsPipeContext = WanLink->PsPipeContext;
|
||
Vc->PsComponent = WanLink->PsComponent;
|
||
}
|
||
else
|
||
{
|
||
|
||
Vc->AdapterStats = &Adapter->Stats;
|
||
Vc->PsPipeContext = Adapter->PsPipeContext;
|
||
Vc->PsComponent = Adapter->PsComponent;
|
||
}
|
||
|
||
*GpcClientVc = Vc;
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
|
||
} // CmCreateVc
|
||
|
||
|
||
|
||
|
||
BOOLEAN
|
||
IsIsslowFlow(
|
||
IN PGPC_CLIENT_VC Vc,
|
||
IN PCO_CALL_PARAMETERS CallParameters
|
||
)
|
||
{
|
||
LONG ParamsLength;
|
||
LPQOS_OBJECT_HDR QoSObject;
|
||
PADAPTER Adapter = Vc->Adapter;
|
||
PCO_MEDIA_PARAMETERS CallMgrParams = CallParameters->MediaParameters;
|
||
ULONGLONG i,j,k;
|
||
|
||
ParamsLength = (LONG)CallMgrParams->MediaSpecific.Length;
|
||
QoSObject = (LPQOS_OBJECT_HDR)CallMgrParams->MediaSpecific.Parameters;
|
||
|
||
while(ParamsLength > 0)
|
||
{
|
||
if(QoSObject->ObjectType == QOS_OBJECT_WAN_MEDIA)
|
||
{
|
||
if((Vc->WanLink->LinkSpeed <= Adapter->ISSLOWLinkSpeed) &&
|
||
(CallParameters->CallMgrParameters->Transmit.ServiceType != SERVICETYPE_BESTEFFORT))
|
||
{
|
||
i = (ULONG) Adapter->ISSLOWTokenRate * (ULONG) CallParameters->CallMgrParameters->Transmit.MaxSduSize;
|
||
j = (ULONG) Adapter->ISSLOWPacketSize * (ULONG) CallParameters->CallMgrParameters->Transmit.TokenRate;
|
||
k = (ULONG) Adapter->ISSLOWTokenRate * (ULONG)Adapter->ISSLOWPacketSize;
|
||
|
||
if((i+j)<k)
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
if( ((LONG)QoSObject->ObjectLength <= 0) ||
|
||
((LONG)QoSObject->ObjectLength > ParamsLength) )
|
||
{
|
||
|
||
return(FALSE);
|
||
}
|
||
|
||
ParamsLength -= QoSObject->ObjectLength;
|
||
QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject + QoSObject->ObjectLength);
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
NDIS_STATUS
|
||
CmMakeCall(
|
||
IN PGPC_CLIENT_VC Vc
|
||
)
|
||
{
|
||
ULONG CmParamsLength;
|
||
NDIS_STATUS Status;
|
||
ULONG RemainingBandWidthChanged;
|
||
PADAPTER Adapter = Vc->Adapter;
|
||
PCO_CALL_PARAMETERS CallParameters = Vc->CallParameters;
|
||
|
||
//
|
||
// Validate parameters
|
||
//
|
||
|
||
Status = ValidateCallParameters(Vc, CallParameters->CallMgrParameters);
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
PsDbgOut(DBG_INFO,
|
||
DBG_VC,
|
||
("[CmMakeCall]: Vc %08X, invalid QoS parameters\n",
|
||
Vc));
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// make sure we can admit the flow onto our adapter. if this
|
||
// succeeds, the resources are committed and we'll have to call
|
||
// CancelAcquiredFlowResources to return them.
|
||
//
|
||
|
||
Status = AcquireFlowResources(Vc,
|
||
CallParameters->CallMgrParameters,
|
||
NULL,
|
||
&RemainingBandWidthChanged);
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
PsDbgOut(DBG_INFO,
|
||
DBG_VC,
|
||
("[CmMakeCall]: Vc %08X, no flow resc\n",
|
||
Vc));
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// In the integrated call manager/miniport model, the activation
|
||
// is internal. Activating the Vc consists of adding the flow to the
|
||
// scheduler. If it succeeds, we will later call NdisMCmActivateVc,
|
||
// just as a courtesy, to notify NDIS.
|
||
//
|
||
|
||
if( Adapter->MediaType == NdisMediumWan &&
|
||
!IsBestEffortVc(Vc) &&
|
||
IsIsslowFlow( Vc, CallParameters ) )
|
||
{
|
||
// Need to do this before we add a flow to the sched components.
|
||
Vc->Flags |= GPC_ISSLOW_FLOW;
|
||
}
|
||
|
||
|
||
Status = AddFlowToScheduler(NEW_VC, Vc, CallParameters, 0);
|
||
|
||
// Let's revert it back, to avoid any side effects..
|
||
Vc->Flags = Vc->Flags & ~GPC_ISSLOW_FLOW;
|
||
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_VC,
|
||
("[CmMakeCall]: Vc %08X, AddFlowToScheduler failed %08X\n",
|
||
Vc,
|
||
Status));
|
||
|
||
CancelAcquiredFlowResources(Vc);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
//
|
||
// A flow has been added to psched after this point. So, whenever the Vc goes away, Psched's flow
|
||
// has to be removed from an explicit call.
|
||
//
|
||
|
||
Vc->bRemoveFlow = TRUE;
|
||
|
||
|
||
//
|
||
// If there is an NDIS 5.0, connection oriented driver below us, then
|
||
// we need to call it, with the call parameters, to complete the VC
|
||
// setup.
|
||
//
|
||
|
||
if(Adapter->MediaType == NdisMediumWan &&
|
||
!IsBestEffortVc(Vc))
|
||
{
|
||
Status = WanMakeCall(Vc, CallParameters);
|
||
|
||
PsAssert(Status == NDIS_STATUS_PENDING);
|
||
|
||
return Status;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// if we made it this far, the MakeCall succeeded!
|
||
//
|
||
Status = ProcessDiffservFlow(Vc, CallParameters->CallMgrParameters);
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_VC,
|
||
("[CmMakeCall]: Vc %08X, AddDiffservMapping failed %08X\n", Vc, Status));
|
||
|
||
CancelAcquiredFlowResources(Vc);
|
||
|
||
return Status;
|
||
}
|
||
|
||
if(TRUE == RemainingBandWidthChanged)
|
||
{
|
||
LONG RemainingBandWidth;
|
||
|
||
PS_LOCK(&Adapter->Lock);
|
||
|
||
RemainingBandWidth = (LONG) Adapter->RemainingBandWidth;
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
|
||
PsTcNotify(Adapter, 0, OID_QOS_REMAINING_BANDWIDTH, &RemainingBandWidth, sizeof(LONG));
|
||
}
|
||
|
||
Vc->TokenRateChange = 0;
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
CompleteMakeCall(
|
||
PGPC_CLIENT_VC Vc,
|
||
PCO_CALL_PARAMETERS CallParameters,
|
||
NDIS_STATUS Status
|
||
)
|
||
{
|
||
PADAPTER Adapter = Vc->Adapter;
|
||
|
||
PsAssert(Adapter->MediaType == NdisMediumWan);
|
||
|
||
PsAssert(!IsBestEffortVc(Vc));
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
CancelAcquiredFlowResources(Vc);
|
||
|
||
}
|
||
else
|
||
{
|
||
Status = ProcessDiffservFlow(Vc, CallParameters->CallMgrParameters);
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_VC,
|
||
("[CompleteMakeCall]: Vc %08X, AddDiffservMapping failed %08X\n", Vc, Status));
|
||
|
||
CancelAcquiredFlowResources(Vc);
|
||
}
|
||
}
|
||
|
||
Vc->TokenRateChange = 0;
|
||
|
||
CmMakeCallComplete(Status, Vc, CallParameters);
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
CmModifyCall(
|
||
IN PGPC_CLIENT_VC Vc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Modify the QoS of an existing flow based on the supplied call params.
|
||
First see if the request can be handled locally.
|
||
|
||
Arguments:
|
||
|
||
See the DDK...
|
||
|
||
Return Values:
|
||
|
||
NDIS_STATUS_SUCCESS if everything worked ok.
|
||
|
||
--*/
|
||
|
||
{
|
||
NDIS_STATUS Status;
|
||
ULONG CmParamsLength;
|
||
PCO_CALL_PARAMETERS CallParameters;
|
||
PADAPTER Adapter;
|
||
ULONG RemainingBandWidthChanged;
|
||
|
||
Adapter = Vc->Adapter;
|
||
PsStructAssert(Adapter);
|
||
|
||
PsAssert(Vc->TokenRateChange == 0);
|
||
|
||
//
|
||
// Validate parameters
|
||
//
|
||
|
||
CallParameters = Vc->ModifyCallParameters;
|
||
Status = ValidateCallParameters(Vc, CallParameters->CallMgrParameters);
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
PsDbgOut(DBG_INFO,
|
||
DBG_VC,
|
||
("[CmModifyCallQoS]: Vc %08X, invalid QoS parameters\n",
|
||
Vc));
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// make sure we can admit the flow onto our adapter. if this
|
||
// succeeds, the resources are committed and we'll have to call
|
||
// CancelAcquiredFlowResources to return them.
|
||
//
|
||
|
||
Status = AcquireFlowResources(Vc,
|
||
CallParameters->CallMgrParameters,
|
||
Vc->CallParameters->CallMgrParameters,
|
||
&RemainingBandWidthChanged);
|
||
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS){
|
||
|
||
PsDbgOut(DBG_INFO,
|
||
DBG_VC,
|
||
("[CmModifyCallQoS]: Vc %08X, no flow resc\n",
|
||
Vc));
|
||
|
||
return Status;
|
||
}
|
||
|
||
Status = AddFlowToScheduler(MODIFY_VC, Vc, CallParameters, Vc->CallParameters);
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS){
|
||
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_VC,
|
||
("[CmModifyCallQoS]: Vc %08X, failed %08X\n",
|
||
Vc,
|
||
Status));
|
||
|
||
//
|
||
// Free the copy we made, Cancel the committed resources.
|
||
//
|
||
|
||
CancelAcquiredFlowResources(Vc);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
//
|
||
// If there is an NDIS 5.0, connection oriented driver below us, then
|
||
// we need to call it, with the call parameters, to complete the VC
|
||
// setup.
|
||
//
|
||
|
||
if(Adapter->MediaType == NdisMediumWan){
|
||
|
||
Status = WanModifyCall(Vc, CallParameters);
|
||
|
||
PsAssert(Status == NDIS_STATUS_PENDING);
|
||
|
||
return(Status);
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// if we made it this far, the ModifyCallQoS succeeded!
|
||
//
|
||
|
||
Status = ProcessDiffservFlow(Vc, CallParameters->CallMgrParameters);
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS) {
|
||
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_VC,
|
||
("[CmModifyCallQos]: Vc %08X, AddDiffservMapping failed %08X\n", Vc, Status));
|
||
|
||
//
|
||
// Undo the add flow done above, by reversing the new and old parameters.
|
||
//
|
||
|
||
ValidateCallParameters(Vc, Vc->CallParameters->CallMgrParameters);
|
||
|
||
AddFlowToScheduler(MODIFY_VC, Vc, Vc->CallParameters, CallParameters);
|
||
|
||
CancelAcquiredFlowResources(Vc);
|
||
|
||
return Status;
|
||
}
|
||
|
||
if(TRUE == RemainingBandWidthChanged) {
|
||
|
||
LONG RemainingBandWidth;
|
||
|
||
PS_LOCK(&Adapter->Lock);
|
||
|
||
RemainingBandWidth = (LONG) Adapter->RemainingBandWidth;
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
|
||
PsTcNotify(Adapter, 0, OID_QOS_REMAINING_BANDWIDTH, &RemainingBandWidth, sizeof(LONG));
|
||
}
|
||
|
||
Vc->TokenRateChange = 0;
|
||
|
||
return(NDIS_STATUS_SUCCESS);
|
||
}
|
||
} // CmModifyCallQoS
|
||
|
||
VOID
|
||
ModifyCallComplete(
|
||
PGPC_CLIENT_VC Vc,
|
||
PCO_CALL_PARAMETERS CallParameters,
|
||
NDIS_STATUS Status
|
||
)
|
||
{
|
||
PADAPTER Adapter = Vc->Adapter;
|
||
|
||
PsAssert(Adapter->MediaType == NdisMediumWan);
|
||
PsAssert(!IsBestEffortVc(Vc));
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS) {
|
||
|
||
//
|
||
// Undo the add flow done above, by reversing the new and old parameters.
|
||
//
|
||
ValidateCallParameters(Vc, Vc->CallParameters->CallMgrParameters);
|
||
|
||
Status = AddFlowToScheduler(MODIFY_VC, Vc, Vc->CallParameters, CallParameters);
|
||
|
||
CancelAcquiredFlowResources(Vc);
|
||
}
|
||
else {
|
||
|
||
Status = ProcessDiffservFlow(Vc, CallParameters->CallMgrParameters);
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS) {
|
||
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_VC,
|
||
("[CmModifyCallQos]: Vc %08X, AddDiffservMapping failed %08X\n", Vc, Status));
|
||
|
||
//
|
||
// Undo the add flow done above, by reversing the new and old parameters.
|
||
//
|
||
ValidateCallParameters(Vc, Vc->CallParameters->CallMgrParameters);
|
||
|
||
AddFlowToScheduler(MODIFY_VC, Vc, Vc->CallParameters, CallParameters);
|
||
|
||
CancelAcquiredFlowResources(Vc);
|
||
|
||
}
|
||
}
|
||
|
||
Vc->TokenRateChange = 0;
|
||
|
||
CmModifyCallComplete(Status, Vc, CallParameters);
|
||
}
|
||
|
||
|
||
|
||
NDIS_STATUS
|
||
CmCloseCall(
|
||
PGPC_CLIENT_VC Vc
|
||
)
|
||
{
|
||
NDIS_STATUS Status;
|
||
PADAPTER Adapter = Vc->Adapter;
|
||
ULONG RemainingBandWidthChanged;
|
||
|
||
PsStructAssert(Adapter);
|
||
//
|
||
// Here, we used to call RemoveFlowFromScheduler, which used to call "DeleteFlow". Instead, we will
|
||
// call a new interface "EmptyPacketsFromScheduler", which will call "EmptyFlow" to empty all the
|
||
// packets queued up in each of the components corresponding to this flow.
|
||
//
|
||
|
||
EmptyPacketsFromScheduler( Vc );
|
||
|
||
RemoveDiffservMapping(Vc);
|
||
|
||
ReturnFlowResources(Vc, &RemainingBandWidthChanged);
|
||
|
||
if(TRUE == RemainingBandWidthChanged) {
|
||
|
||
LONG RemainingBandWidth;
|
||
|
||
PS_LOCK(&Adapter->Lock);
|
||
|
||
RemainingBandWidth = (LONG) Adapter->RemainingBandWidth;
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
|
||
PsTcNotify(Adapter, 0, OID_QOS_REMAINING_BANDWIDTH, &RemainingBandWidth, sizeof(LONG));
|
||
}
|
||
|
||
if(!IsBestEffortVc(Vc))
|
||
{
|
||
CmCloseCallComplete(NDIS_STATUS_SUCCESS, Vc);
|
||
}
|
||
else
|
||
{
|
||
DerefClVc(Vc);
|
||
}
|
||
|
||
return NDIS_STATUS_PENDING;
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
CmDeleteVc(
|
||
IN PGPC_CLIENT_VC Vc
|
||
)
|
||
{
|
||
|
||
PsAssert(Vc->RefCount == 0);
|
||
|
||
if(Vc->InstanceName.Buffer) {
|
||
|
||
PsFreePool(Vc->InstanceName.Buffer);
|
||
}
|
||
|
||
if( Vc->bRemoveFlow)
|
||
{
|
||
Vc->bRemoveFlow = FALSE;
|
||
RemoveFlowFromScheduler(Vc);
|
||
}
|
||
|
||
if(Vc->PsFlowContext) {
|
||
|
||
if(Vc->Adapter->MediaType == NdisMediumWan) {
|
||
|
||
if(Vc->PsFlowContext != Vc->WanLink->BestEffortVc.PsFlowContext) {
|
||
|
||
PsFreePool(Vc->PsFlowContext);
|
||
}
|
||
else {
|
||
|
||
if(Vc == &Vc->WanLink->BestEffortVc) {
|
||
|
||
PsFreePool(Vc->PsFlowContext);
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
|
||
if(Vc->PsFlowContext != Vc->Adapter->BestEffortVc.PsFlowContext) {
|
||
|
||
PsFreePool(Vc->PsFlowContext);
|
||
}
|
||
else {
|
||
|
||
if(Vc == &Vc->Adapter->BestEffortVc) {
|
||
|
||
PsFreePool(Vc->PsFlowContext);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
NdisFreeSpinLock(&Vc->Lock);
|
||
|
||
NdisFreeSpinLock(&Vc->BytesScheduledLock);
|
||
|
||
NdisFreeSpinLock(&Vc->BytesTransmittedLock);
|
||
|
||
|
||
if(Vc->CallParameters){
|
||
|
||
PsFreePool(Vc->CallParameters);
|
||
Vc->CallParameters = NULL;
|
||
}
|
||
|
||
|
||
if(!IsBestEffortVc(Vc))
|
||
{
|
||
PS_LOCK(&Vc->Adapter->Lock);
|
||
|
||
RemoveEntryList(&Vc->Linkage);
|
||
|
||
PS_UNLOCK(&Vc->Adapter->Lock);
|
||
|
||
if(Vc->Flags & GPC_WANLINK_VC)
|
||
{
|
||
REFDEL(&Vc->WanLink->RefCount, FALSE, 'WANV');
|
||
}
|
||
|
||
REFDEL(&Vc->Adapter->RefCount, FALSE, 'ADVC');
|
||
|
||
|
||
PsFreeToLL(Vc, &GpcClientVcLL, GpcClientVc);
|
||
}
|
||
else
|
||
{
|
||
PADAPTER Adapter = Vc->Adapter;
|
||
|
||
if(Vc->Flags & GPC_WANLINK_VC)
|
||
{
|
||
REFDEL(&Vc->WanLink->RefCount, FALSE, 'WANV');
|
||
}
|
||
|
||
REFDEL(&Adapter->RefCount, FALSE, 'ADVC');
|
||
}
|
||
|
||
return(NDIS_STATUS_SUCCESS);
|
||
|
||
} // CmDeleteVc
|
||
|
||
|
||
VOID
|
||
FillInCmParams(
|
||
PCO_CALL_MANAGER_PARAMETERS CmParams,
|
||
SERVICETYPE ServiceType,
|
||
ULONG TokenRate,
|
||
ULONG PeakBandwidth,
|
||
ULONG TokenBucketSize,
|
||
ULONG DSMode,
|
||
ULONG Priority)
|
||
{
|
||
PCO_SPECIFIC_PARAMETERS SpecificParameters;
|
||
QOS_SD_MODE * QoSObjectSDMode;
|
||
QOS_PRIORITY * QoSObjectPriority;
|
||
QOS_OBJECT_HDR * QoSObjectHdr;
|
||
|
||
CmParams->Transmit.ServiceType = ServiceType;
|
||
CmParams->Transmit.TokenRate = TokenRate;
|
||
CmParams->Transmit.PeakBandwidth = PeakBandwidth;
|
||
CmParams->Transmit.TokenBucketSize = TokenBucketSize;
|
||
|
||
CmParams->CallMgrSpecific.ParamType = PARAM_TYPE_GQOS_INFO;
|
||
CmParams->CallMgrSpecific.Length = 0;
|
||
|
||
SpecificParameters =
|
||
(PCO_SPECIFIC_PARAMETERS)&CmParams->CallMgrSpecific.Parameters;
|
||
|
||
if(DSMode != QOS_UNSPECIFIED){
|
||
|
||
CmParams->CallMgrSpecific.Length += sizeof(QOS_SD_MODE);
|
||
QoSObjectSDMode = (QOS_SD_MODE *)SpecificParameters;
|
||
QoSObjectSDMode->ObjectHdr.ObjectType = QOS_OBJECT_SD_MODE;
|
||
QoSObjectSDMode->ObjectHdr.ObjectLength = sizeof(QOS_SD_MODE);
|
||
QoSObjectSDMode->ShapeDiscardMode = DSMode;
|
||
(QOS_SD_MODE *)SpecificParameters++;
|
||
}
|
||
|
||
if(Priority != QOS_UNSPECIFIED){
|
||
|
||
CmParams->CallMgrSpecific.Length += sizeof(QOS_PRIORITY);
|
||
QoSObjectPriority = (QOS_PRIORITY *)SpecificParameters;
|
||
QoSObjectPriority->ObjectHdr.ObjectType = QOS_OBJECT_PRIORITY;
|
||
QoSObjectPriority->ObjectHdr.ObjectLength = sizeof(QOS_PRIORITY);
|
||
QoSObjectPriority->SendPriority = (UCHAR)Priority;
|
||
(QOS_PRIORITY *)SpecificParameters++;
|
||
}
|
||
|
||
QoSObjectHdr = (QOS_OBJECT_HDR *)SpecificParameters;
|
||
QoSObjectHdr->ObjectType = QOS_OBJECT_END_OF_LIST;
|
||
QoSObjectHdr->ObjectLength = sizeof(QOS_OBJECT_HDR);
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
ValidateCallParameters(
|
||
PGPC_CLIENT_VC Vc,
|
||
PCO_CALL_MANAGER_PARAMETERS CallParameters
|
||
)
|
||
{
|
||
ULONG TokenRate = CallParameters->Transmit.TokenRate;
|
||
SERVICETYPE ServiceType = CallParameters->Transmit.ServiceType;
|
||
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
||
UCHAR SendPriority;
|
||
ULONG SDMode;
|
||
ULONG PeakBandwidth;
|
||
LONG ParamsLength;
|
||
LPQOS_OBJECT_HDR QoSObject;
|
||
ULONG Class;
|
||
ULONG DSFieldCount;
|
||
LPQOS_DIFFSERV_RULE pDiffServRule;
|
||
ULONG i;
|
||
ULONG ShapingRate;
|
||
|
||
ParamsLength = (LONG)CallParameters->CallMgrSpecific.Length;
|
||
PeakBandwidth = CallParameters->Transmit.PeakBandwidth;
|
||
|
||
//
|
||
// By default, we want to shape to the TokenRate
|
||
//
|
||
Vc->ShapeTokenRate = TokenRate;
|
||
|
||
QoSObject = (LPQOS_OBJECT_HDR)CallParameters->CallMgrSpecific.Parameters;
|
||
|
||
while(ParamsLength > 0){
|
||
|
||
switch(QoSObject->ObjectType){
|
||
|
||
case QOS_OBJECT_TRAFFIC_CLASS:
|
||
|
||
Class = (((LPQOS_TRAFFIC_CLASS)QoSObject)->TrafficClass);
|
||
|
||
if(Class > USER_PRIORITY_MAX_VALUE)
|
||
{
|
||
return QOS_STATUS_INVALID_TRAFFIC_CLASS;
|
||
}
|
||
|
||
break;
|
||
|
||
case QOS_OBJECT_DS_CLASS:
|
||
|
||
Class = (((LPQOS_DS_CLASS)QoSObject)->DSField);
|
||
|
||
if(Class > PREC_MAX_VALUE)
|
||
{
|
||
return QOS_STATUS_INVALID_DS_CLASS;
|
||
}
|
||
|
||
break;
|
||
|
||
case QOS_OBJECT_SHAPING_RATE:
|
||
|
||
ShapingRate = (((LPQOS_SHAPING_RATE)QoSObject)->ShapingRate);
|
||
|
||
if(ShapingRate == 0 || ShapingRate > TokenRate)
|
||
{
|
||
return QOS_STATUS_INVALID_SHAPE_RATE;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// If this QoS object is present, we want to shape to this
|
||
// rate.
|
||
//
|
||
Vc->ShapeTokenRate = ShapingRate;
|
||
}
|
||
|
||
break;
|
||
|
||
case QOS_OBJECT_DIFFSERV:
|
||
|
||
DSFieldCount = (((LPQOS_DIFFSERV)QoSObject)->DSFieldCount);
|
||
|
||
if(!DSFieldCount) {
|
||
|
||
return QOS_STATUS_INVALID_DIFFSERV_FLOW;
|
||
}
|
||
|
||
pDiffServRule = ((LPQOS_DIFFSERV_RULE)((LPQOS_DIFFSERV)QoSObject)->DiffservRule);
|
||
|
||
for(i=0; i<DSFieldCount; i++, pDiffServRule++) {
|
||
|
||
if(pDiffServRule->InboundDSField > PREC_MAX_VALUE ||
|
||
pDiffServRule->ConformingOutboundDSField > PREC_MAX_VALUE ||
|
||
pDiffServRule->NonConformingOutboundDSField > PREC_MAX_VALUE ||
|
||
pDiffServRule->ConformingUserPriority > USER_PRIORITY_MAX_VALUE ||
|
||
pDiffServRule->NonConformingUserPriority > USER_PRIORITY_MAX_VALUE ) {
|
||
|
||
return QOS_STATUS_INVALID_DIFFSERV_FLOW;
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
|
||
case QOS_OBJECT_PRIORITY:
|
||
|
||
SendPriority = ((LPQOS_PRIORITY)QoSObject)->SendPriority;
|
||
|
||
if((SendPriority < 0) || (SendPriority > 7)){
|
||
|
||
// bad priority value - reject
|
||
|
||
return(QOS_STATUS_INVALID_QOS_PRIORITY);
|
||
}
|
||
|
||
break;
|
||
|
||
case QOS_OBJECT_SD_MODE:
|
||
|
||
SDMode = ((LPQOS_SD_MODE)QoSObject)->ShapeDiscardMode;
|
||
|
||
//
|
||
// Since SDMode is a ULONG, it can never be < TC_NONCONF_BORROW, which has a value of 0.
|
||
// so, we just check to see if SDMode is > TC_NONCONF_BORROW_PLUS. This covers all cases.
|
||
//
|
||
|
||
if(SDMode > TC_NONCONF_BORROW_PLUS){
|
||
|
||
// bad shape discard mode - reject
|
||
|
||
return(QOS_STATUS_INVALID_SD_MODE);
|
||
}
|
||
|
||
if((SDMode > TC_NONCONF_BORROW) &&
|
||
(TokenRate == UNSPECIFIED_RATE)){
|
||
|
||
// must have TokenRate specified if any SDMode
|
||
// other than TC_NONCONF_BORROW
|
||
|
||
return(QOS_STATUS_INVALID_TOKEN_RATE);
|
||
}
|
||
|
||
break;
|
||
|
||
// Pass any provider specific objects that we don't recognize
|
||
|
||
}
|
||
|
||
if(
|
||
((LONG)QoSObject->ObjectLength <= 0) ||
|
||
((LONG)QoSObject->ObjectLength > ParamsLength)
|
||
){
|
||
|
||
return(QOS_STATUS_TC_OBJECT_LENGTH_INVALID);
|
||
}
|
||
|
||
ParamsLength -= QoSObject->ObjectLength;
|
||
QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject +
|
||
QoSObject->ObjectLength);
|
||
|
||
}
|
||
|
||
//
|
||
// If there is a specified PeakBandwidth, it must be geq to the
|
||
// TokenRate - meaning - there must be a TokenRate specified also.
|
||
// This is reasonable for LAN, although ATM does allow a
|
||
// PeakBandwidth to be specified with no TokenRate.
|
||
//
|
||
// We also reject a TokenRate of zero.
|
||
//
|
||
|
||
if(PeakBandwidth != UNSPECIFIED_RATE){
|
||
|
||
if(TokenRate == UNSPECIFIED_RATE){
|
||
|
||
return(QOS_STATUS_INVALID_PEAK_RATE);
|
||
}
|
||
|
||
if(TokenRate > PeakBandwidth){
|
||
|
||
return(QOS_STATUS_INVALID_PEAK_RATE);
|
||
}
|
||
}
|
||
|
||
if(TokenRate == 0){
|
||
|
||
return(QOS_STATUS_INVALID_TOKEN_RATE);
|
||
}
|
||
|
||
switch(ServiceType){
|
||
|
||
case SERVICETYPE_BESTEFFORT:
|
||
case SERVICETYPE_NETWORK_CONTROL:
|
||
case SERVICETYPE_QUALITATIVE:
|
||
|
||
break;
|
||
|
||
case SERVICETYPE_CONTROLLEDLOAD:
|
||
case SERVICETYPE_GUARANTEED:
|
||
|
||
// Must specify a TokenRate for these services
|
||
|
||
if(TokenRate == QOS_UNSPECIFIED) {
|
||
|
||
return(QOS_STATUS_INVALID_TOKEN_RATE);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
|
||
return(QOS_STATUS_INVALID_SERVICE_TYPE);
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
NDIS_STATUS
|
||
AcquireFlowResources(
|
||
PGPC_CLIENT_VC Vc,
|
||
PCO_CALL_MANAGER_PARAMETERS NewCallParams,
|
||
PCO_CALL_MANAGER_PARAMETERS OldCallParams,
|
||
PULONG RemainingBandWidthChanged
|
||
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
See if this adapter can support the requested flow. If it can,
|
||
NDIS_STATUS_SUCCESS is returned, indicating that the resources
|
||
have been committed.
|
||
|
||
Arguments:
|
||
|
||
Vc - pointer to vc's context block
|
||
NewCallParams - struct describing the flow to add or to modify to.
|
||
OldCallParams - in case of a modify, this describes the old params.
|
||
|
||
|
||
Return Value:
|
||
|
||
NDIS_STATUS_SUCCESS if everything worked ok
|
||
|
||
--*/
|
||
|
||
{
|
||
PADAPTER Adapter;
|
||
ULONG OldTokenRate;
|
||
SERVICETYPE OldServiceType;
|
||
ULONG NewTokenRate = NewCallParams->Transmit.TokenRate;
|
||
SERVICETYPE NewServiceType = NewCallParams->Transmit.ServiceType;
|
||
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
||
PULONG RemainingBandWidth;
|
||
PULONG NonBestEffortLimit;
|
||
PPS_SPIN_LOCK Lock;
|
||
|
||
Adapter = Vc->Adapter;
|
||
PsStructAssert(Adapter);
|
||
|
||
*RemainingBandWidthChanged = FALSE;
|
||
|
||
if(Adapter->MediaType == NdisMediumWan && (!IsBestEffortVc(Vc)))
|
||
{
|
||
RemainingBandWidth = &Vc->WanLink->RemainingBandWidth;
|
||
NonBestEffortLimit = &Vc->WanLink->NonBestEffortLimit;
|
||
Lock = &Vc->WanLink->Lock;
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
RemainingBandWidth = &Adapter->RemainingBandWidth;
|
||
NonBestEffortLimit = &Adapter->NonBestEffortLimit;
|
||
Lock = &Adapter->Lock;
|
||
}
|
||
|
||
|
||
if(OldCallParams)
|
||
{
|
||
OldTokenRate = OldCallParams->Transmit.TokenRate;
|
||
OldServiceType = OldCallParams->Transmit.ServiceType;
|
||
}
|
||
|
||
//
|
||
// sanity check passed; now see if we have the resouces locally
|
||
//
|
||
// for best-effort flows, the token rate, for the purpose of
|
||
// admission control, is considered to be zero
|
||
//
|
||
|
||
if(NewServiceType == SERVICETYPE_BESTEFFORT || NewServiceType == SERVICETYPE_NETWORK_CONTROL ||
|
||
NewServiceType == SERVICETYPE_QUALITATIVE)
|
||
{
|
||
|
||
NewTokenRate = 0;
|
||
}
|
||
|
||
//
|
||
// Handle add differently from a modify
|
||
//
|
||
|
||
if(!OldCallParams){
|
||
|
||
PS_LOCK(Lock);
|
||
|
||
if((((LONG)(*RemainingBandWidth)) < 0) || (NewTokenRate > *RemainingBandWidth)){
|
||
|
||
PS_UNLOCK(Lock);
|
||
|
||
return(NDIS_STATUS_RESOURCES);
|
||
|
||
}
|
||
else{
|
||
|
||
if(NewTokenRate) {
|
||
|
||
*RemainingBandWidthChanged = TRUE;
|
||
}
|
||
|
||
*RemainingBandWidth -= NewTokenRate;
|
||
|
||
//
|
||
// Record the change we made, in case we have
|
||
// to cancel the addition.
|
||
//
|
||
|
||
Vc->TokenRateChange = NewTokenRate;
|
||
Vc->RemainingBandwidthIncreased = FALSE;
|
||
|
||
PsAssert((*RemainingBandWidth <= *NonBestEffortLimit));
|
||
|
||
PS_UNLOCK(Lock);
|
||
}
|
||
}
|
||
else{
|
||
|
||
//
|
||
// it's a modify
|
||
//
|
||
// If the OldServiceType is best-effort,
|
||
// then the OldTokenRate can be considered
|
||
// to be zero, for the purpose of admission control.
|
||
//
|
||
|
||
if(OldServiceType == SERVICETYPE_BESTEFFORT ||
|
||
OldServiceType == SERVICETYPE_NETWORK_CONTROL ||
|
||
OldServiceType == SERVICETYPE_QUALITATIVE)
|
||
{
|
||
|
||
OldTokenRate = 0;
|
||
}
|
||
|
||
PS_LOCK(Lock);
|
||
|
||
if(NewTokenRate != OldTokenRate){
|
||
|
||
if((((LONG) *RemainingBandWidth) < 0 )||
|
||
((NewTokenRate > OldTokenRate) &&
|
||
((NewTokenRate - OldTokenRate) >
|
||
(*RemainingBandWidth)))){
|
||
|
||
//
|
||
// asked for more and none was available
|
||
//
|
||
|
||
PS_UNLOCK( Lock );
|
||
|
||
return(NDIS_STATUS_RESOURCES);
|
||
|
||
}
|
||
else{
|
||
|
||
//
|
||
// either asked for less or rate increment was available
|
||
//
|
||
|
||
*RemainingBandWidth -= NewTokenRate;
|
||
*RemainingBandWidth += OldTokenRate;
|
||
|
||
if((NewTokenRate != 0) || (OldTokenRate != 0)) {
|
||
|
||
*RemainingBandWidthChanged = TRUE;
|
||
}
|
||
|
||
//
|
||
// Now we've acquired the resources. If
|
||
// the VC activation fails for any reason,
|
||
// we'll need to return resources. We should
|
||
// return the difference between the old token
|
||
// rate and the new token rate, not the new token
|
||
// rate.
|
||
//
|
||
|
||
if(NewTokenRate > OldTokenRate){
|
||
|
||
// Can't use signed ints, cause we'll lose range
|
||
|
||
Vc->TokenRateChange = NewTokenRate - OldTokenRate;
|
||
Vc->RemainingBandwidthIncreased = FALSE;
|
||
|
||
}
|
||
else{
|
||
|
||
Vc->TokenRateChange = OldTokenRate - NewTokenRate;
|
||
Vc->RemainingBandwidthIncreased = TRUE;
|
||
}
|
||
|
||
PS_UNLOCK( Lock );
|
||
}
|
||
}
|
||
else{
|
||
|
||
PS_UNLOCK(Lock);
|
||
}
|
||
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // AcquireFlowResources
|
||
|
||
VOID
|
||
CancelAcquiredFlowResources(
|
||
PGPC_CLIENT_VC Vc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called when a modify or add flwo failed, after we did admission control.
|
||
|
||
Arguments:
|
||
|
||
Vc - pointer to client vc's context block
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
PADAPTER Adapter;
|
||
PPS_SPIN_LOCK Lock;
|
||
PULONG RemainingBandWidth;
|
||
|
||
Adapter = Vc->Adapter;
|
||
PsStructAssert(Adapter);
|
||
|
||
if(Adapter->MediaType == NdisMediumWan && (!IsBestEffortVc(Vc)))
|
||
{
|
||
Lock = &Vc->WanLink->Lock;
|
||
RemainingBandWidth = &Vc->WanLink->RemainingBandWidth;
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
Lock = &Adapter->Lock;
|
||
RemainingBandWidth = &Adapter->RemainingBandWidth;
|
||
}
|
||
|
||
if(!Vc->TokenRateChange){
|
||
|
||
return;
|
||
}
|
||
|
||
PS_LOCK( Lock );
|
||
|
||
if(Vc->RemainingBandwidthIncreased){
|
||
|
||
*RemainingBandWidth -= Vc->TokenRateChange;
|
||
}
|
||
else{
|
||
|
||
*RemainingBandWidth += Vc->TokenRateChange;
|
||
}
|
||
|
||
//
|
||
// Now that we have already returned the correct TokenRate, we need to set it to 0
|
||
// so that this is not used in subsequent VC operations.
|
||
//
|
||
|
||
Vc->TokenRateChange = 0;
|
||
|
||
// PsAssert(Adapter->RemainingBandWidth <= Adapter->NonBestEffortLimit);
|
||
|
||
PS_UNLOCK( Lock );
|
||
|
||
} // CancelAcquiredFlowResources
|
||
|
||
|
||
VOID
|
||
ReturnFlowResources(
|
||
PGPC_CLIENT_VC Vc,
|
||
PULONG RemainingBandWidthChanged
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Return all the resources acquired for this flow
|
||
|
||
Arguments:
|
||
|
||
Vc - pointer to client vc's context block
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
PADAPTER Adapter;
|
||
PCO_CALL_MANAGER_PARAMETERS CmParams = Vc->CallParameters->CallMgrParameters;
|
||
ULONG TokenRate = CmParams->Transmit.TokenRate;
|
||
SERVICETYPE ServiceType = CmParams->Transmit.ServiceType;
|
||
PPS_SPIN_LOCK Lock;
|
||
PULONG RemainingBandWidth;
|
||
|
||
Adapter = Vc->Adapter;
|
||
PsStructAssert(Adapter);
|
||
|
||
*RemainingBandWidthChanged = FALSE;
|
||
|
||
if(Adapter->MediaType == NdisMediumWan && (!IsBestEffortVc(Vc)))
|
||
{
|
||
RemainingBandWidth = &Vc->WanLink->RemainingBandWidth;
|
||
Lock = &Vc->WanLink->Lock;
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
RemainingBandWidth = &Adapter->RemainingBandWidth;
|
||
Lock = &Adapter->Lock;
|
||
}
|
||
|
||
if (ServiceType == SERVICETYPE_BESTEFFORT ||
|
||
ServiceType == SERVICETYPE_NETWORK_CONTROL ||
|
||
ServiceType == SERVICETYPE_QUALITATIVE)
|
||
{
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
*RemainingBandWidthChanged = TRUE;
|
||
|
||
PsAssert((LONG)TokenRate > 0);
|
||
|
||
PS_LOCK( Lock );
|
||
|
||
*RemainingBandWidth += TokenRate;
|
||
|
||
// PsAssert(Adapter->RemainingBandWidth <= Adapter->NonBestEffortLimit);
|
||
|
||
PS_UNLOCK( Lock );
|
||
|
||
} // ReturnFlowResources
|
||
|
||
|
||
NDIS_STATUS
|
||
CreateBestEffortVc(
|
||
PADAPTER Adapter,
|
||
PGPC_CLIENT_VC Vc,
|
||
PPS_WAN_LINK WanLink
|
||
)
|
||
{
|
||
PCO_CALL_PARAMETERS CallParams;
|
||
PCO_CALL_MANAGER_PARAMETERS CallMgrParameters;
|
||
PCO_MEDIA_PARAMETERS MediaParameters;
|
||
ULONG CallParamsLength;
|
||
NDIS_STATUS Status;
|
||
int i;
|
||
|
||
|
||
InitGpcClientVc(Vc, GPC_CLIENT_BEST_EFFORT_VC, Adapter);
|
||
SetLLTag(Vc, GpcClientVc);
|
||
|
||
//
|
||
// Invalidate all the port numbers
|
||
for( i = 0; i < PORT_LIST_LEN; i++)
|
||
{
|
||
Vc->SrcPort[i] = 0xffff;
|
||
Vc->DstPort[i] = 0xffff;
|
||
}
|
||
|
||
// Next Insertion will be at index 0
|
||
Vc->NextSlot = 0;
|
||
|
||
//
|
||
// Allocate the resources for the call manager parameters.
|
||
//
|
||
|
||
CallParamsLength = sizeof(CO_CALL_PARAMETERS) +
|
||
sizeof(CO_CALL_MANAGER_PARAMETERS) +
|
||
sizeof(QOS_SD_MODE) +
|
||
sizeof(QOS_OBJECT_HDR) +
|
||
FIELD_OFFSET(CO_MEDIA_PARAMETERS, MediaSpecific) +
|
||
FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters);
|
||
|
||
if(Adapter->MediaType == NdisMediumWan)
|
||
{
|
||
CallParamsLength += sizeof(QOS_WAN_MEDIA);
|
||
Vc->PsPipeContext = WanLink->PsPipeContext;
|
||
Vc->PsComponent = WanLink->PsComponent;
|
||
Vc->AdapterStats = &WanLink->Stats;
|
||
Vc->WanLink = WanLink;
|
||
Vc->Flags |= GPC_WANLINK_VC;
|
||
|
||
if(Adapter->BestEffortLimit != UNSPECIFIED_RATE)
|
||
{
|
||
//
|
||
// If LBE is specified over WAN, use UBE
|
||
//
|
||
|
||
PsAdapterWriteEventLog(
|
||
EVENT_PS_WAN_LIMITED_BESTEFFORT,
|
||
0,
|
||
&Adapter->MpDeviceName,
|
||
0,
|
||
NULL);
|
||
|
||
Adapter->BestEffortLimit = UNSPECIFIED_RATE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Vc->PsPipeContext = Adapter->PsPipeContext;
|
||
Vc->PsComponent = Adapter->PsComponent;
|
||
Vc->AdapterStats = &Adapter->Stats;
|
||
}
|
||
|
||
PsAllocatePool(CallParams, CallParamsLength, CmParamsTag);
|
||
|
||
if(CallParams == NULL)
|
||
{
|
||
return NDIS_STATUS_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// build a call params struct describing the flow
|
||
//
|
||
|
||
NdisZeroMemory(CallParams, CallParamsLength);
|
||
|
||
//
|
||
// Build the Call Manager Parameters.
|
||
//
|
||
CallMgrParameters = (PCO_CALL_MANAGER_PARAMETERS)(CallParams + 1);
|
||
|
||
if(Adapter->BestEffortLimit == UNSPECIFIED_RATE)
|
||
{
|
||
FillInCmParams(CallMgrParameters,
|
||
SERVICETYPE_BESTEFFORT,
|
||
(ULONG)UNSPECIFIED_RATE,
|
||
(ULONG)UNSPECIFIED_RATE,
|
||
Adapter->TotalSize,
|
||
QOS_UNSPECIFIED,
|
||
QOS_UNSPECIFIED);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Limited Best Effort
|
||
//
|
||
|
||
PsAssert(Adapter->MediaType != NdisMediumWan);
|
||
|
||
if(Adapter->BestEffortLimit >= Adapter->LinkSpeed) {
|
||
|
||
// If the specified limit is greater than the link speed,
|
||
// then we should operate in unlimited best-effort mode.
|
||
|
||
|
||
PsAdapterWriteEventLog(
|
||
EVENT_PS_BAD_BESTEFFORT_LIMIT,
|
||
0,
|
||
&Adapter->MpDeviceName,
|
||
0,
|
||
NULL);
|
||
|
||
PsDbgOut(DBG_INFO,
|
||
DBG_PROTOCOL,
|
||
("[CreateBestEffortVc]: b/e limit %d exceeds link speed %d\n",
|
||
Adapter->BestEffortLimit,
|
||
Adapter->LinkSpeed));
|
||
|
||
Adapter->BestEffortLimit = UNSPECIFIED_RATE;
|
||
|
||
FillInCmParams(CallMgrParameters,
|
||
SERVICETYPE_BESTEFFORT,
|
||
(ULONG)UNSPECIFIED_RATE,
|
||
(ULONG)UNSPECIFIED_RATE,
|
||
Adapter->TotalSize,
|
||
QOS_UNSPECIFIED,
|
||
QOS_UNSPECIFIED);
|
||
|
||
}
|
||
else
|
||
{
|
||
FillInCmParams(CallMgrParameters,
|
||
SERVICETYPE_BESTEFFORT,
|
||
Adapter->BestEffortLimit,
|
||
(ULONG)UNSPECIFIED_RATE,
|
||
Adapter->TotalSize,
|
||
TC_NONCONF_SHAPE,
|
||
QOS_UNSPECIFIED);
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Build the MediaParameters.
|
||
//
|
||
|
||
CallParams->MediaParameters =
|
||
(PCO_MEDIA_PARAMETERS)(CallMgrParameters + 1);
|
||
|
||
MediaParameters = (PCO_MEDIA_PARAMETERS)((PUCHAR)
|
||
CallMgrParameters +
|
||
sizeof(CO_CALL_MANAGER_PARAMETERS) +
|
||
sizeof(QOS_SD_MODE) +
|
||
sizeof(QOS_OBJECT_HDR));
|
||
|
||
MediaParameters->Flags = 0;
|
||
MediaParameters->ReceivePriority = 0;
|
||
MediaParameters->ReceiveSizeHint = 0;
|
||
MediaParameters->MediaSpecific.ParamType = PARAM_TYPE_GQOS_INFO;
|
||
MediaParameters->MediaSpecific.Length = 0;
|
||
|
||
CallParams->Flags = 0;
|
||
CallParams->CallMgrParameters = CallMgrParameters;
|
||
CallParams->MediaParameters = (PCO_MEDIA_PARAMETERS)MediaParameters;
|
||
|
||
if(Adapter->MediaType == NdisMediumWan) {
|
||
|
||
LPQOS_WAN_MEDIA WanMedia;
|
||
MediaParameters->MediaSpecific.Length += sizeof(QOS_WAN_MEDIA);
|
||
WanMedia = (LPQOS_WAN_MEDIA) MediaParameters->MediaSpecific.Parameters;
|
||
|
||
NdisZeroMemory(WanMedia, sizeof(QOS_WAN_MEDIA));
|
||
|
||
WanMedia->ObjectHdr.ObjectType = QOS_OBJECT_WAN_MEDIA;
|
||
WanMedia->ObjectHdr.ObjectLength = sizeof(QOS_WAN_MEDIA);
|
||
|
||
NdisMoveMemory(&WanMedia->LinkId,
|
||
&WanLink->OriginalRemoteMacAddress,
|
||
6);
|
||
|
||
}
|
||
|
||
Vc->CallParameters = CallParams;
|
||
|
||
Status = CmMakeCall(Vc);
|
||
|
||
PsAssert(Status != NDIS_STATUS_PENDING);
|
||
|
||
if(Status == NDIS_STATUS_SUCCESS)
|
||
{
|
||
|
||
REFADD(&Adapter->RefCount, 'ADVC');
|
||
if(Adapter->MediaType == NdisMediumWan)
|
||
{
|
||
REFADD(&WanLink->RefCount, 'WANV');
|
||
}
|
||
//
|
||
// Also save the non conforming value - so that the sequencer can stamp it
|
||
// for non conforming packets. This will not change between reboots & hence
|
||
// need not be done in the ModifyCfInfo
|
||
//
|
||
|
||
Vc->UserPriorityNonConforming = Adapter->UserServiceTypeNonConforming;
|
||
|
||
switch(Vc->CallParameters->CallMgrParameters->Transmit.ServiceType)
|
||
{
|
||
case SERVICETYPE_CONTROLLEDLOAD:
|
||
Vc->UserPriorityConforming = Adapter->UserServiceTypeControlledLoad;
|
||
Vc->IPPrecedenceNonConforming = Adapter->IPServiceTypeControlledLoadNC;
|
||
break;
|
||
case SERVICETYPE_GUARANTEED:
|
||
Vc->UserPriorityConforming = Adapter->UserServiceTypeGuaranteed;
|
||
Vc->IPPrecedenceNonConforming = Adapter->IPServiceTypeGuaranteedNC;
|
||
break;
|
||
case SERVICETYPE_BESTEFFORT:
|
||
Vc->UserPriorityConforming = Adapter->UserServiceTypeBestEffort;
|
||
Vc->IPPrecedenceNonConforming = Adapter->IPServiceTypeBestEffortNC;
|
||
break;
|
||
case SERVICETYPE_QUALITATIVE:
|
||
Vc->UserPriorityConforming = Adapter->UserServiceTypeQualitative;
|
||
Vc->IPPrecedenceNonConforming = Adapter->IPServiceTypeQualitativeNC;
|
||
break;
|
||
case SERVICETYPE_NETWORK_CONTROL:
|
||
Vc->UserPriorityConforming = Adapter->UserServiceTypeNetworkControl;
|
||
Vc->IPPrecedenceNonConforming = Adapter->IPServiceTypeNetworkControlNC;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Transistion to the Call complete state
|
||
//
|
||
|
||
CallSucceededStateTransition(Vc);
|
||
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NDIS_STATUS
|
||
RemoveDiffservMapping(
|
||
PGPC_CLIENT_VC Vc
|
||
)
|
||
{
|
||
LPQOS_OBJECT_HDR QoSObject;
|
||
ULONG ParamsLength;
|
||
ULONG DSFieldCount;
|
||
LPQOS_DIFFSERV_RULE pDiffServRule;
|
||
ULONG i;
|
||
PADAPTER Adapter = Vc->Adapter;
|
||
PCO_CALL_MANAGER_PARAMETERS CallParameters = Vc->CallParameters->CallMgrParameters;
|
||
PDIFFSERV_MAPPING pDiffServMapping;
|
||
|
||
ParamsLength = (LONG)CallParameters->CallMgrSpecific.Length;
|
||
|
||
QoSObject = (LPQOS_OBJECT_HDR)CallParameters->CallMgrSpecific.Parameters;
|
||
|
||
while(ParamsLength > 0) {
|
||
|
||
if(QoSObject->ObjectType == QOS_OBJECT_DIFFSERV)
|
||
{
|
||
|
||
DSFieldCount = (((LPQOS_DIFFSERV)QoSObject)->DSFieldCount);
|
||
|
||
//
|
||
// Make sure that everything that we are clearing is mapped to the same Vc.
|
||
//
|
||
|
||
PS_LOCK(&Adapter->Lock);
|
||
|
||
if(Vc->WanLink)
|
||
{
|
||
pDiffServMapping = Vc->WanLink->pDiffServMapping;
|
||
}
|
||
else
|
||
{
|
||
pDiffServMapping = Vc->Adapter->pDiffServMapping;
|
||
}
|
||
|
||
for(i=0, pDiffServRule = ((LPQOS_DIFFSERV_RULE)((LPQOS_DIFFSERV)QoSObject)->DiffservRule);
|
||
i<DSFieldCount;
|
||
i++, pDiffServRule++)
|
||
{
|
||
UCHAR tos = pDiffServRule->InboundDSField;
|
||
|
||
if(pDiffServMapping[tos].Vc == Vc) {
|
||
|
||
pDiffServMapping[tos].Vc = 0;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We are trying to remove a codepoint that is mapped to another VC. Ideally, this
|
||
// should never happen. We still need to check that this is a valid VC (otherwise, if
|
||
// a diffserv rule has the same codepoint more than one time, we could still hit this
|
||
// assert, because the first codepoint will clear the mapping and the second codepoint
|
||
// will see the NULL - so we check if the Vc is non null)
|
||
//
|
||
|
||
if(pDiffServMapping[tos].Vc)
|
||
{
|
||
PsDbgOut(DBG_FAILURE, DBG_VC,
|
||
("[RemoveDiffservMapping]: Vc %08X, Trying to remove codepoint %d that "
|
||
"is mapped to Vc %08X \n",
|
||
Vc,
|
||
pDiffServRule->InboundDSField,
|
||
pDiffServMapping[pDiffServRule->InboundDSField].Vc));
|
||
|
||
PsAssert(0);
|
||
}
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
|
||
//
|
||
// Make sure that no TOS mapping points to this VC.
|
||
//
|
||
|
||
for(i=0; i<=PREC_MAX_VALUE; i++) {
|
||
|
||
PsAssert(pDiffServMapping[i].Vc != Vc);
|
||
}
|
||
#endif
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
|
||
ParamsLength -= QoSObject->ObjectLength;
|
||
|
||
QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject +
|
||
QoSObject->ObjectLength);
|
||
}
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
|
||
NDIS_STATUS
|
||
ProcessDiffservFlow(
|
||
PGPC_CLIENT_VC Vc,
|
||
PCO_CALL_MANAGER_PARAMETERS CallParameters)
|
||
{
|
||
LPQOS_OBJECT_HDR QoSObject;
|
||
ULONG ParamsLength;
|
||
ULONG DSFieldCount;
|
||
LPQOS_DIFFSERV_RULE pDiffServRule;
|
||
ULONG i;
|
||
PGPC_CLIENT_VC CurrentVc;
|
||
PADAPTER Adapter = Vc->Adapter;
|
||
PDIFFSERV_MAPPING pDiffServMapping;
|
||
PDIFFSERV_MAPPING *pD;
|
||
|
||
ParamsLength = (LONG)CallParameters->CallMgrSpecific.Length;
|
||
QoSObject = (LPQOS_OBJECT_HDR)CallParameters->CallMgrSpecific.Parameters;
|
||
|
||
while(ParamsLength > 0)
|
||
{
|
||
if(QoSObject->ObjectType == QOS_OBJECT_DIFFSERV)
|
||
{
|
||
|
||
//
|
||
// We have found the diffserv QoS object. This could be due to a add or modify of
|
||
// the flow. If this is an add, we are okay. If it is a modify, there are 2 cases.
|
||
// 1. Modify from an RSVP flow to a Diffserv Flow.
|
||
// 2. Modify from a diffserv flow to another diffserv flow.
|
||
//
|
||
|
||
DSFieldCount = (((LPQOS_DIFFSERV)QoSObject)->DSFieldCount);
|
||
|
||
PS_LOCK(&Adapter->Lock);
|
||
|
||
if(Vc->WanLink)
|
||
{
|
||
pDiffServMapping = Vc->WanLink->pDiffServMapping;
|
||
pD = &Vc->WanLink->pDiffServMapping;
|
||
}
|
||
else
|
||
{
|
||
pDiffServMapping = Vc->Adapter->pDiffServMapping;
|
||
pD = &Vc->Adapter->pDiffServMapping;
|
||
}
|
||
|
||
if(pDiffServMapping == 0)
|
||
{
|
||
//
|
||
// To optimize on memory, we allocate the diffserv mapping only when someone creates
|
||
// a Diffserv flow on that adapter or wanlink.
|
||
//
|
||
// We could further optimize this by freeing this when the last diffserv flow went
|
||
// away - For now, we assume that if a Diffserv flow is created on an interface, then the
|
||
// interface is probably going to be used for Diffserv mode till the next reboot. This is
|
||
// not such a bad assumption, because the Diffserv mode is meaningful only on routers
|
||
// and we don't expect to switch b/w these modes very often.
|
||
//
|
||
|
||
PsAllocatePool(*pD,
|
||
sizeof(DIFFSERV_MAPPING) * (PREC_MAX_VALUE+1),
|
||
PsMiscTag);
|
||
|
||
if(*pD == 0)
|
||
{
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
return NDIS_STATUS_RESOURCES;
|
||
}
|
||
else
|
||
{
|
||
NdisZeroMemory(*pD, sizeof(DIFFSERV_MAPPING) * (PREC_MAX_VALUE+1));
|
||
}
|
||
|
||
pDiffServMapping = *pD;
|
||
}
|
||
|
||
|
||
//
|
||
// Make sure that everything is either unmapped, or is mapped to the same vc (for modify)
|
||
//
|
||
|
||
for(i=0, pDiffServRule = ((LPQOS_DIFFSERV_RULE)((LPQOS_DIFFSERV)QoSObject)->DiffservRule);
|
||
i<DSFieldCount;
|
||
i++, pDiffServRule++)
|
||
{
|
||
|
||
uchar tos = pDiffServRule->InboundDSField;
|
||
CurrentVc = pDiffServMapping[tos].Vc;
|
||
|
||
if(CurrentVc) {
|
||
|
||
if(CurrentVc != Vc) {
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
|
||
PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
|
||
("[ProcessDiffservFlow]: Adapter %08X, Vc%08X: CodePoint %d already "
|
||
" mapped to Vc 0x%x \n",
|
||
Adapter,
|
||
Vc,
|
||
pDiffServRule->InboundDSField,
|
||
CurrentVc));
|
||
|
||
return QOS_STATUS_DS_MAPPING_EXISTS;
|
||
}
|
||
|
||
PsAssert(Vc->ModifyCallParameters);
|
||
|
||
}
|
||
}
|
||
|
||
|
||
if(Vc->ModifyCallParameters) {
|
||
|
||
//
|
||
// for a modify, we need to unmap the ones that are not there in this rule
|
||
//
|
||
|
||
for(i=0; i<=PREC_MAX_VALUE; i++) {
|
||
|
||
if(pDiffServMapping[i].Vc == Vc) {
|
||
|
||
pDiffServMapping[i].Vc = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Map (or re-map)
|
||
//
|
||
|
||
for(i=0, pDiffServRule = ((LPQOS_DIFFSERV_RULE)((LPQOS_DIFFSERV)QoSObject)->DiffservRule);
|
||
i<DSFieldCount;
|
||
i++, pDiffServRule++)
|
||
{
|
||
|
||
uchar tos = pDiffServRule->InboundDSField;
|
||
|
||
pDiffServMapping[tos].Vc = Vc;
|
||
|
||
pDiffServMapping[tos].ConformingOutboundDSField =
|
||
pDiffServRule->ConformingOutboundDSField << 2;
|
||
|
||
pDiffServMapping[tos].NonConformingOutboundDSField =
|
||
pDiffServRule->NonConformingOutboundDSField << 2;
|
||
|
||
pDiffServMapping[tos].ConformingUserPriority =
|
||
pDiffServRule->ConformingUserPriority;
|
||
|
||
pDiffServMapping[tos].NonConformingUserPriority =
|
||
pDiffServRule->NonConformingUserPriority;
|
||
|
||
}
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
|
||
ParamsLength -= QoSObject->ObjectLength;
|
||
|
||
QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject +
|
||
QoSObject->ObjectLength);
|
||
}
|
||
|
||
//
|
||
// This is a RSVP flow. If this is a modify, we need to unmap existing diffserv flows, because
|
||
// we could be changing this from a Diffserv Flow to a RSVP flow.
|
||
//
|
||
|
||
if(Vc->ModifyCallParameters)
|
||
{
|
||
//
|
||
// for a modify, we need to unmap the ones that are not there in this rule
|
||
//
|
||
|
||
PS_LOCK(&Adapter->Lock);
|
||
|
||
if(Vc->WanLink)
|
||
{
|
||
pDiffServMapping = Vc->WanLink->pDiffServMapping;
|
||
}
|
||
else
|
||
{
|
||
pDiffServMapping = Vc->Adapter->pDiffServMapping;
|
||
}
|
||
|
||
if(pDiffServMapping)
|
||
{
|
||
|
||
for(i=0; i<=PREC_MAX_VALUE; i++)
|
||
{
|
||
if(pDiffServMapping[i].Vc == Vc)
|
||
{
|
||
pDiffServMapping[i].Vc = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
}
|
||
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
|
||
/* end cmvc.c */
|