|
|
/*++
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 */
|