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.
1523 lines
40 KiB
1523 lines
40 KiB
/*++
|
|
|
|
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
|
|
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 = (ULONGLONG) Adapter->ISSLOWTokenRate * (ULONGLONG) CallParameters->CallMgrParameters->Transmit.MaxSduSize;
|
|
j = (ULONGLONG) Adapter->ISSLOWPacketSize * (ULONGLONG) CallParameters->CallMgrParameters->Transmit.TokenRate;
|
|
k = (ULONGLONG) Adapter->ISSLOWTokenRate * (ULONGLONG)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(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);
|
|
|
|
}
|
|
|
|
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(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);
|
|
}
|
|
|
|
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 );
|
|
|
|
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 > sizeof(QOS_OBJECT_HDR)) {
|
|
|
|
switch(QoSObject->ObjectType){
|
|
|
|
case QOS_OBJECT_TRAFFIC_CLASS:
|
|
|
|
if (ParamsLength < sizeof(QOS_TRAFFIC_CLASS))
|
|
return QOS_STATUS_TC_OBJECT_LENGTH_INVALID;
|
|
|
|
Class = (((LPQOS_TRAFFIC_CLASS)QoSObject)->TrafficClass);
|
|
|
|
if(Class > USER_PRIORITY_MAX_VALUE)
|
|
{
|
|
return QOS_STATUS_INVALID_TRAFFIC_CLASS;
|
|
}
|
|
|
|
break;
|
|
|
|
case QOS_OBJECT_DS_CLASS:
|
|
|
|
if (ParamsLength < sizeof(QOS_DS_CLASS))
|
|
return QOS_STATUS_TC_OBJECT_LENGTH_INVALID;
|
|
|
|
Class = (((LPQOS_DS_CLASS)QoSObject)->DSField);
|
|
|
|
if(Class > PREC_MAX_VALUE)
|
|
{
|
|
return QOS_STATUS_INVALID_DS_CLASS;
|
|
}
|
|
|
|
break;
|
|
|
|
case QOS_OBJECT_SHAPING_RATE:
|
|
|
|
if (ParamsLength < sizeof(QOS_SHAPING_RATE))
|
|
return QOS_STATUS_TC_OBJECT_LENGTH_INVALID;
|
|
|
|
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_PRIORITY:
|
|
|
|
if (ParamsLength < sizeof(QOS_PRIORITY))
|
|
return QOS_STATUS_TC_OBJECT_LENGTH_INVALID;
|
|
|
|
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:
|
|
|
|
if (ParamsLength < sizeof(QOS_SD_MODE))
|
|
return QOS_STATUS_TC_OBJECT_LENGTH_INVALID;
|
|
|
|
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
|
|
default:
|
|
return(QOS_STATUS_TC_OBJECT_LENGTH_INVALID);
|
|
}
|
|
|
|
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 (ParamsLength == sizeof(QOS_OBJECT_HDR)) {
|
|
if (QoSObject->ObjectType != QOS_OBJECT_END_OF_LIST) {
|
|
return(QOS_STATUS_TC_OBJECT_LENGTH_INVALID);
|
|
}
|
|
} else if (ParamsLength != 0) {
|
|
return(QOS_STATUS_TC_OBJECT_LENGTH_INVALID);
|
|
}
|
|
|
|
//
|
|
// 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] = 0;
|
|
Vc->DstPort[i] = 0;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
/* end cmvc.c */
|