1390 lines
40 KiB
C
1390 lines
40 KiB
C
/*++
|
|
|
|
Copyright (c) 1996-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
GpcHndlr.c
|
|
|
|
Abstract:
|
|
|
|
Handlers called by GPC.
|
|
|
|
Author:
|
|
|
|
Rajesh Sundaram (rajeshsu)
|
|
|
|
Environment:
|
|
|
|
Kernel Mode
|
|
|
|
Revision History:
|
|
|
|
One of the initial designs (yoramb/charliew/rajeshsu) consisted of an
|
|
integrated call manager with a seperate packet classifying client. The
|
|
design used NDIS 5.0 VCs so that they could be managed by WMI.
|
|
|
|
The main limitation of the above approach was the fact that NDIS provided
|
|
mechanisms to manage miniport and VCs - We really needed a way to
|
|
manage other things (like WanLinks, etc).
|
|
|
|
--*/
|
|
|
|
#include "psched.h"
|
|
#pragma hdrstop
|
|
|
|
/* External */
|
|
|
|
/* Static */
|
|
|
|
|
|
GPC_STATUS
|
|
QosAddCfInfoNotify(
|
|
IN GPC_CLIENT_HANDLE ClientContext,
|
|
IN GPC_HANDLE GpcCfInfoHandle,
|
|
IN ULONG CfInfoSize,
|
|
IN PVOID CfInfoPtr,
|
|
IN PGPC_CLIENT_HANDLE ClientCfInfoContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A new CF_INFO has been added to the GPC database.
|
|
|
|
Arguments:
|
|
|
|
ClientContext - Client context supplied to GpcRegisterClient
|
|
GpcCfInfoHandle - GPC's handle to CF_INFO
|
|
CfInfoPtr - Pointer to the CF_INFO structure
|
|
ClientCfInfoContext - Location in which to return PS's context for CF_INFO
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
|
|
{
|
|
PADAPTER Adapter;
|
|
PGPC_CLIENT_VC Vc;
|
|
PCF_INFO_QOS CfInfo;
|
|
NDIS_STATUS Status;
|
|
ULONG CallParamsLength;
|
|
PCO_CALL_PARAMETERS CallParams = 0;
|
|
PCO_CALL_MANAGER_PARAMETERS CallMgrParams;
|
|
PCO_MEDIA_PARAMETERS PsMediaParameters;
|
|
LPQOS_PRIORITY PriorityObject;
|
|
PPS_WAN_LINK WanLink = 0;
|
|
ULONG TcObjAlignedLength;
|
|
|
|
CfInfo = (PCF_INFO_QOS)CfInfoPtr;
|
|
|
|
//
|
|
// Verify that the TcObjectsLength is consistent with the CfInfoSize. The
|
|
// CfInfoSize must have been verified during the user/kernel transition.
|
|
// The TcObjectsLength has not. We could bugcheck if we try to search
|
|
// beyond the buffer passed in.
|
|
//
|
|
|
|
if(CfInfoSize < (FIELD_OFFSET(CF_INFO_QOS, GenFlow) +
|
|
FIELD_OFFSET(TC_GEN_FLOW, TcObjects) +
|
|
CfInfo->GenFlow.TcObjectsLength))
|
|
{
|
|
|
|
PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
|
|
("[QosAddCfInfoNotify]: TcObjectsLength inconsistent with "
|
|
"CfInfoSize \n"));
|
|
|
|
return(QOS_STATUS_TC_OBJECT_LENGTH_INVALID);
|
|
}
|
|
|
|
//
|
|
// Using the instance name, we find the adapter or the wanlink. If the adapter or wanlink is not
|
|
// ready to accept VCs, this function will return NULL. Also, if it is ready, it will take a ref
|
|
// on the Adapter and the WanLink.
|
|
//
|
|
|
|
Adapter = FindAdapterByWmiInstanceName((USHORT) CfInfo->InstanceNameLength,
|
|
(PWSTR) &CfInfo->InstanceName[0],
|
|
&WanLink);
|
|
if(NULL == Adapter)
|
|
{
|
|
PsAssert(WanLink == NULL);
|
|
|
|
PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
|
|
("[QosAddCfInfoNotify]: no adapter with instance name %ws\n",
|
|
CfInfo->InstanceName));
|
|
|
|
return GPC_STATUS_IGNORED;
|
|
}
|
|
|
|
//
|
|
// We have taken a ref on the adapter or wanlink. so we need to deref if we bail out with error. If
|
|
// we create the VC, then the adapter and wanlink are deref'd when the VC is deleted.
|
|
//
|
|
|
|
do
|
|
{
|
|
|
|
//
|
|
// Allocate the resources for the call manager parameters.
|
|
//
|
|
TcObjAlignedLength = ((CfInfo->GenFlow.TcObjectsLength + (sizeof(PVOID)-1)) & ~(sizeof(PVOID)-1));
|
|
|
|
CallParamsLength =
|
|
sizeof(CO_CALL_PARAMETERS) +
|
|
FIELD_OFFSET(CO_CALL_MANAGER_PARAMETERS, CallMgrSpecific) +
|
|
FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters) +
|
|
TcObjAlignedLength +
|
|
FIELD_OFFSET(CO_MEDIA_PARAMETERS, MediaSpecific) +
|
|
FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters);
|
|
|
|
if(Adapter->MediaType == NdisMediumWan)
|
|
{
|
|
CallParamsLength += sizeof(QOS_WAN_MEDIA);
|
|
}
|
|
else
|
|
{
|
|
if(!Adapter->PipeHasResources)
|
|
{
|
|
//
|
|
// We don't want to pend GPC client VCs. The reasons are:
|
|
//
|
|
// a. If the cable is never plugged in, we could pend VCs indefinitely.
|
|
// Waste of system resources.
|
|
//
|
|
// b. There is no clean way for the app to cancel these pended VCs. Since
|
|
// we have pended the AddCfInfo to the GPC, the GPC cannot call back
|
|
// and ask us to delete the VC.
|
|
//
|
|
// But, we still need to handle the case where link speed change
|
|
// might be transient (10/100 case). Also, if we return error, the app
|
|
// might retry causing busy cycles if the media is never connected.
|
|
// For all this, the app can register for WMI notifications for GUIDs
|
|
// GUID_NDIS_STATUS_MEDIA_(DIS)CONNECT
|
|
//
|
|
//
|
|
// Also, we probably don't want to do this for the b/e VC. Otherwise,
|
|
// how does it work when the user installs psched and the media is
|
|
// unconnected ? Do we want him to reinstall psched after connecting
|
|
// the media ?
|
|
//
|
|
|
|
PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
|
|
("[QosAddCfInfoNotify]: Adapter %08X is not plugged in \n", Adapter));
|
|
|
|
Status = NDIS_STATUS_NETWORK_UNREACHABLE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
PsAllocatePool(CallParams, CallParamsLength, CmParamsTag);
|
|
|
|
if(CallParams == NULL) {
|
|
|
|
PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
|
|
("[QosAddCfInfoNotify]: Adapter %08X, can't allocate call"
|
|
"params \n", Adapter));
|
|
|
|
Status = GPC_STATUS_RESOURCES;
|
|
|
|
break;
|
|
}
|
|
|
|
Status = CmCreateVc(&Vc, Adapter, WanLink, CallParams, GpcCfInfoHandle, CfInfo,
|
|
ClientContext);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
|
|
("[QosAddCfInfoNotify]: Adapter %08X, Could not create Vc \n",
|
|
Adapter));
|
|
|
|
break;
|
|
}
|
|
|
|
*ClientCfInfoContext = Vc;
|
|
|
|
} while(FALSE);
|
|
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
if(CallParams)
|
|
{
|
|
PsFreePool(CallParams);
|
|
}
|
|
|
|
if(WanLink)
|
|
{
|
|
REFDEL(&WanLink->RefCount, FALSE, 'WANV');
|
|
}
|
|
|
|
REFDEL(&Adapter->RefCount, FALSE, 'ADVC');
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
//
|
|
// Create a call parameters struct for the MakeCall
|
|
//
|
|
|
|
CallMgrParams = (PCO_CALL_MANAGER_PARAMETERS)(CallParams + 1);
|
|
CallMgrParams->Transmit = CfInfo->GenFlow.SendingFlowspec;
|
|
CallMgrParams->Receive = CfInfo->GenFlow.ReceivingFlowspec;
|
|
CallMgrParams->CallMgrSpecific.ParamType = PARAM_TYPE_GQOS_INFO;
|
|
CallMgrParams->CallMgrSpecific.Length = CfInfo->GenFlow.TcObjectsLength;
|
|
|
|
if(CfInfo->GenFlow.TcObjectsLength > 0){
|
|
|
|
NdisMoveMemory(
|
|
&CallMgrParams->CallMgrSpecific.Parameters,
|
|
&CfInfo->GenFlow.TcObjects,
|
|
CfInfo->GenFlow.TcObjectsLength);
|
|
}
|
|
|
|
PsMediaParameters =
|
|
(PCO_MEDIA_PARAMETERS)((PUCHAR)CallMgrParams +
|
|
FIELD_OFFSET(CO_CALL_MANAGER_PARAMETERS, CallMgrSpecific) +
|
|
FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters) +
|
|
TcObjAlignedLength);
|
|
|
|
PsMediaParameters->Flags = 0;
|
|
PsMediaParameters->ReceivePriority = 0;
|
|
PsMediaParameters->ReceiveSizeHint = CfInfo->GenFlow.SendingFlowspec.MaxSduSize;
|
|
PsMediaParameters->MediaSpecific.ParamType = PARAM_TYPE_GQOS_INFO;
|
|
PsMediaParameters->MediaSpecific.Length = 0;
|
|
|
|
//
|
|
// If this flow is being installed on a Wan interface, need to
|
|
// insert the linkId into the media specific fields. This is so that
|
|
// NdisWan will be able to recognize the link over which to install
|
|
// the flow.
|
|
//
|
|
|
|
if(WanLink){
|
|
|
|
LPQOS_WAN_MEDIA WanMedia;
|
|
PsMediaParameters->MediaSpecific.Length += sizeof(QOS_WAN_MEDIA);
|
|
WanMedia = (LPQOS_WAN_MEDIA) PsMediaParameters->MediaSpecific.Parameters;
|
|
|
|
WanMedia->ObjectHdr.ObjectType = QOS_OBJECT_WAN_MEDIA;
|
|
WanMedia->ObjectHdr.ObjectLength = sizeof(QOS_WAN_MEDIA);
|
|
|
|
NdisMoveMemory(&WanMedia->LinkId,
|
|
WanLink->OriginalRemoteMacAddress,
|
|
6);
|
|
}
|
|
|
|
CallParams->Flags = 0;
|
|
CallParams->CallMgrParameters = CallMgrParams;
|
|
CallParams->MediaParameters = (PCO_MEDIA_PARAMETERS)PsMediaParameters;
|
|
|
|
Status = CmMakeCall(Vc);
|
|
|
|
if(NDIS_STATUS_PENDING != Status)
|
|
{
|
|
CmMakeCallComplete(Status, Vc, Vc->CallParameters);
|
|
}
|
|
|
|
PsDbgOut(DBG_TRACE,
|
|
DBG_GPC_QOS,
|
|
("[QosAddCfInfoNotify]: Adapter %08X, Created Vc %08X - returned "
|
|
" PENDING \n", Adapter, Vc));
|
|
|
|
#if DBG
|
|
NdisInterlockedIncrement(&Adapter->GpcNotifyPending);
|
|
#endif
|
|
|
|
return GPC_STATUS_PENDING;
|
|
}
|
|
|
|
VOID
|
|
SetTOSIEEEValues(PGPC_CLIENT_VC Vc)
|
|
{
|
|
ULONG ServiceType = Vc->CallParameters->CallMgrParameters->Transmit.ServiceType;
|
|
LPQOS_OBJECT_HDR QoSObject;
|
|
LONG ParamsLength;
|
|
LPQOS_TRAFFIC_CLASS Tc;
|
|
LPQOS_DS_CLASS Ds;
|
|
PCF_INFO_QOS CfInfo = (PCF_INFO_QOS) Vc->CfInfoQoS;
|
|
|
|
//
|
|
// Set these based on the ServiceType
|
|
//
|
|
switch(ServiceType)
|
|
{
|
|
case SERVICETYPE_CONTROLLEDLOAD:
|
|
Vc->UserPriorityConforming = Vc->Adapter->UserServiceTypeControlledLoad;
|
|
CfInfo->ToSValue = Vc->Adapter->IPServiceTypeControlledLoad;
|
|
Vc->IPPrecedenceNonConforming = Vc->Adapter->IPServiceTypeControlledLoadNC;
|
|
break;
|
|
case SERVICETYPE_GUARANTEED:
|
|
Vc->UserPriorityConforming = Vc->Adapter->UserServiceTypeGuaranteed;
|
|
Vc->IPPrecedenceNonConforming = Vc->Adapter->IPServiceTypeGuaranteedNC;
|
|
CfInfo->ToSValue = Vc->Adapter->IPServiceTypeGuaranteed;
|
|
break;
|
|
case SERVICETYPE_BESTEFFORT:
|
|
Vc->UserPriorityConforming = Vc->Adapter->UserServiceTypeBestEffort;
|
|
CfInfo->ToSValue = Vc->Adapter->IPServiceTypeBestEffort;
|
|
Vc->IPPrecedenceNonConforming = Vc->Adapter->IPServiceTypeBestEffortNC;
|
|
break;
|
|
case SERVICETYPE_QUALITATIVE:
|
|
Vc->UserPriorityConforming = Vc->Adapter->UserServiceTypeQualitative;
|
|
CfInfo->ToSValue = Vc->Adapter->IPServiceTypeQualitative;
|
|
Vc->IPPrecedenceNonConforming = Vc->Adapter->IPServiceTypeQualitativeNC;
|
|
break;
|
|
case SERVICETYPE_NETWORK_CONTROL:
|
|
Vc->UserPriorityConforming = Vc->Adapter->UserServiceTypeNetworkControl;
|
|
CfInfo->ToSValue = Vc->Adapter->IPServiceTypeNetworkControl;
|
|
Vc->IPPrecedenceNonConforming = Vc->Adapter->IPServiceTypeNetworkControlNC;
|
|
break;
|
|
}
|
|
Vc->UserPriorityNonConforming = Vc->Adapter->UserServiceTypeNonConforming;
|
|
|
|
//
|
|
// Walk the QoS objects to see if there is a TCLASS or a DCLASS
|
|
//
|
|
ParamsLength = (LONG)Vc->CallParameters->CallMgrParameters->CallMgrSpecific.Length;
|
|
QoSObject = (LPQOS_OBJECT_HDR)Vc->CallParameters->CallMgrParameters->CallMgrSpecific.Parameters;
|
|
|
|
while(ParamsLength > 0) {
|
|
|
|
switch(QoSObject->ObjectType)
|
|
{
|
|
case QOS_OBJECT_TCP_TRAFFIC:
|
|
|
|
//
|
|
// This QoS object asks us to override the ServiceType, the TCLASS and the DCLASS markings.
|
|
// so, if we fidn this QoS object, we set the values, and return.
|
|
//
|
|
|
|
Vc->UserPriorityConforming = (UCHAR) Vc->Adapter->UserServiceTypeTcpTraffic;
|
|
CfInfo->ToSValue = (UCHAR) Vc->Adapter->IPServiceTypeTcpTraffic;
|
|
Vc->IPPrecedenceNonConforming = (UCHAR) Vc->Adapter->IPServiceTypeTcpTrafficNC;
|
|
return;
|
|
|
|
case QOS_OBJECT_TRAFFIC_CLASS:
|
|
|
|
Tc = (LPQOS_TRAFFIC_CLASS)QoSObject;
|
|
Vc->UserPriorityConforming = (UCHAR) Tc->TrafficClass;
|
|
break;
|
|
|
|
case QOS_OBJECT_DS_CLASS:
|
|
Ds = (LPQOS_DS_CLASS)QoSObject;
|
|
CfInfo->ToSValue = Ds->DSField << 2;
|
|
break;
|
|
}
|
|
|
|
ParamsLength -= QoSObject->ObjectLength;
|
|
|
|
QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject +
|
|
QoSObject->ObjectLength);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
VOID
|
|
CmMakeCallComplete(NDIS_STATUS Status, PGPC_CLIENT_VC Vc,
|
|
PCO_CALL_PARAMETERS CallParameters)
|
|
{
|
|
PADAPTER Adapter = Vc->Adapter;
|
|
GPC_HANDLE CfInfo = Vc->CfInfoHandle;
|
|
PPS_WAN_LINK WanLink = Vc->WanLink;
|
|
ULONG CurrentFlows;
|
|
LARGE_INTEGER Increment;
|
|
LARGE_INTEGER VcIndex;
|
|
|
|
PsAssert(!IsBestEffortVc(Vc));
|
|
|
|
Increment.QuadPart = 1;
|
|
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
|
|
//
|
|
// Create an Instance name for this VC and register with WMI.
|
|
//
|
|
VcIndex = ExInterlockedAddLargeInteger(&Adapter->VcIndex, Increment, &Adapter->Lock.Lock.SpinLock);
|
|
|
|
Status = GenerateInstanceName(&VcPrefix, Vc->Adapter, &VcIndex, &Vc->InstanceName);
|
|
|
|
//
|
|
// Transistion from CL_CALL_PENDING to CL_INTERNAL_CALL_COMPLETE
|
|
//
|
|
|
|
CallSucceededStateTransition(Vc);
|
|
|
|
|
|
PS_LOCK(&Vc->Lock);
|
|
|
|
SetTOSIEEEValues(Vc);
|
|
|
|
PS_UNLOCK(&Vc->Lock);
|
|
|
|
if(Adapter->MediaType == NdisMediumWan) {
|
|
|
|
|
|
//
|
|
// This variable is used to optimize the send path
|
|
//
|
|
InterlockedIncrement(&WanLink->CfInfosInstalled);
|
|
|
|
if((Vc->Flags & GPC_ISSLOW_FLOW)) {
|
|
|
|
//
|
|
// Tell NDISWAN about the fragment size
|
|
//
|
|
MakeLocalNdisRequest(Adapter,
|
|
Vc->NdisWanVcHandle,
|
|
NdisRequestLocalSetInfo,
|
|
OID_QOS_ISSLOW_FRAGMENT_SIZE,
|
|
&Vc->ISSLOWFragmentSize,
|
|
sizeof(ULONG),
|
|
NULL);
|
|
}
|
|
|
|
//
|
|
// This is used for OID_QOS_FLOW_COUNT - Better be thread safe
|
|
//
|
|
|
|
PS_LOCK(&WanLink->Lock);
|
|
|
|
WanLink->FlowsInstalled ++;
|
|
|
|
CurrentFlows = WanLink->FlowsInstalled;
|
|
|
|
PS_UNLOCK(&WanLink->Lock);
|
|
|
|
PsTcNotify(Adapter, WanLink, OID_QOS_FLOW_COUNT, &CurrentFlows, sizeof(ULONG));
|
|
}
|
|
else {
|
|
|
|
//
|
|
// This variable is used to optimize the send path
|
|
//
|
|
InterlockedIncrement(&Adapter->CfInfosInstalled);
|
|
|
|
PS_LOCK(&Adapter->Lock);
|
|
|
|
Adapter->FlowsInstalled ++;
|
|
|
|
CurrentFlows = Adapter->FlowsInstalled;
|
|
|
|
PS_UNLOCK(&Adapter->Lock);
|
|
|
|
PsTcNotify(Adapter, 0, OID_QOS_FLOW_COUNT, &CurrentFlows, sizeof(ULONG));
|
|
|
|
}
|
|
|
|
//
|
|
// Update Stats
|
|
//
|
|
|
|
InterlockedIncrement(&Vc->AdapterStats->FlowsOpened);
|
|
Vc->AdapterStats->MaxSimultaneousFlows =
|
|
max(Vc->AdapterStats->MaxSimultaneousFlows, CurrentFlows);
|
|
|
|
//
|
|
// Notify the GPC
|
|
//
|
|
|
|
|
|
PsDbgOut(DBG_TRACE,
|
|
DBG_GPC_QOS,
|
|
("[CmMakeCallComplete]: Adapter %08X, Vc %08X succeeded - "
|
|
" Notify GPC \n", Adapter, Vc));
|
|
|
|
GpcEntries.GpcAddCfInfoNotifyCompleteHandler(GpcQosClientHandle,
|
|
CfInfo,
|
|
Status,
|
|
Vc);
|
|
|
|
//
|
|
// Transistion from CL_INTERNAL_CALL_COMPLETE to CL_CALL_COMPLETE
|
|
//
|
|
|
|
CallSucceededStateTransition(Vc);
|
|
|
|
|
|
}
|
|
else {
|
|
|
|
PsDbgOut(DBG_FAILURE,
|
|
DBG_GPC_QOS,
|
|
("[CmMakeCallComplete]: Adapter %08X, Vc %08X, Make Call failed. Status = %x\n",
|
|
Adapter, Vc, Status));
|
|
|
|
InterlockedIncrement(&Vc->AdapterStats->FlowsRejected);
|
|
|
|
GpcEntries.GpcAddCfInfoNotifyCompleteHandler(GpcQosClientHandle,
|
|
CfInfo,
|
|
Status,
|
|
Vc);
|
|
|
|
DerefClVc(Vc);
|
|
}
|
|
|
|
#if DBG
|
|
NdisInterlockedDecrement(&Adapter->GpcNotifyPending);
|
|
#endif
|
|
|
|
} // CmMakeCallComplete
|
|
|
|
GPC_STATUS
|
|
QosClGetCfInfoName(
|
|
IN GPC_CLIENT_HANDLE ClientContext,
|
|
IN GPC_CLIENT_HANDLE ClientCfInfoContext,
|
|
OUT PNDIS_STRING InstanceName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
The GPC can issue this call to get from us the WMI manageable
|
|
InstanceName which Ndis created for the flow associated with
|
|
the CfInfo struct.
|
|
|
|
We guarantee to keep the string buffer around until the CfInfo
|
|
structure is removed.
|
|
|
|
Arguments:
|
|
|
|
ClientContext - Client context supplied to GpcRegisterClient
|
|
GpcCfInfoHandle - GPC's handle to CF_INFO
|
|
InstanceName - We return a pointer to our string.
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PGPC_CLIENT_VC GpcClientVc = (PGPC_CLIENT_VC)ClientCfInfoContext;
|
|
|
|
if(GpcClientVc->InstanceName.Buffer){
|
|
|
|
InstanceName->Buffer = GpcClientVc->InstanceName.Buffer;
|
|
InstanceName->Length = GpcClientVc->InstanceName.Length;
|
|
InstanceName->MaximumLength =
|
|
GpcClientVc->InstanceName.MaximumLength;
|
|
|
|
return(NDIS_STATUS_SUCCESS);
|
|
}
|
|
else{
|
|
|
|
return(NDIS_STATUS_FAILURE);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
QosAddCfInfoComplete(
|
|
IN GPC_CLIENT_HANDLE ClientContext,
|
|
IN GPC_CLIENT_HANDLE ClientCfInfoContext,
|
|
IN GPC_STATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The GPC has completed processing an AddCfInfo request.
|
|
|
|
Arguments:
|
|
|
|
ClientContext - Client context supplied to GpcRegisterClient
|
|
ClientCfInfoContext - CfInfo context
|
|
Status - Final status
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// The PS never adds CF_INFO's so this routine should never be called
|
|
//
|
|
|
|
DEBUGCHK;
|
|
|
|
} // QosAddCfInfoComplete
|
|
|
|
|
|
GPC_STATUS
|
|
QosModifyCfInfoNotify(
|
|
IN GPC_CLIENT_HANDLE ClientContext,
|
|
IN GPC_CLIENT_HANDLE ClientCfInfoContext,
|
|
IN ULONG CfInfoSize,
|
|
IN PVOID NewCfInfoPtr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A CF_INFO is being modified.
|
|
|
|
Arguments:
|
|
|
|
ClientContext - Client context supplied to GpcRegisterClient
|
|
ClientCfInfoContext - CfInfo context
|
|
NewCfInfoPtr - Pointer to proposed CF_INFO content
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
|
|
{
|
|
PGPC_CLIENT_VC GpcClientVc = (PGPC_CLIENT_VC)ClientCfInfoContext;
|
|
PCF_INFO_QOS NewCfInfo = (PCF_INFO_QOS)NewCfInfoPtr;
|
|
NDIS_STATUS Status;
|
|
ULONG CallParamsLength;
|
|
PCO_CALL_PARAMETERS CallParams;
|
|
PCO_CALL_MANAGER_PARAMETERS CallMgrParams;
|
|
PCO_MEDIA_PARAMETERS PsMediaParameters;
|
|
LPQOS_PRIORITY PriorityObject;
|
|
PADAPTER Adapter;
|
|
ULONG TcObjAlignedLength;
|
|
|
|
//
|
|
// Do sanity checks
|
|
//
|
|
|
|
//
|
|
// Verify that the TcObjectsLength is consistent with the
|
|
// CfInfoSize. The CfInfoSize must have been verified during
|
|
// the user/kernel transition. The TcObjectsLength has not.
|
|
// We could bugcheck if we try to search beyond the buffer
|
|
// passed in.
|
|
//
|
|
|
|
if(CfInfoSize < (FIELD_OFFSET(CF_INFO_QOS, GenFlow) +
|
|
FIELD_OFFSET(TC_GEN_FLOW, TcObjects) +
|
|
NewCfInfo->GenFlow.TcObjectsLength)){
|
|
|
|
PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
|
|
("[QosModifyCfInfoNotify]: TcObjectsLength inconsistent with "
|
|
"CfInfoSize \n"));
|
|
|
|
return(ERROR_TC_OBJECT_LENGTH_INVALID);
|
|
}
|
|
|
|
Adapter = GpcClientVc->Adapter;
|
|
|
|
PS_LOCK(&Adapter->Lock);
|
|
|
|
if(Adapter->PsMpState != AdapterStateRunning) {
|
|
|
|
PS_UNLOCK(&Adapter->Lock);
|
|
|
|
PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
|
|
("[QosModifyCfInfoNotify]: Adapter %08X closing, cannot accept "
|
|
"modify request \n", Adapter));
|
|
|
|
return GPC_STATUS_NOTREADY;
|
|
}
|
|
PS_UNLOCK(&Adapter->Lock);
|
|
|
|
//
|
|
// Allocate the resources for the call manager parameters
|
|
//
|
|
|
|
TcObjAlignedLength = ((NewCfInfo->GenFlow.TcObjectsLength + (sizeof(PVOID)-1)) & ~(sizeof(PVOID)-1));
|
|
CallParamsLength =
|
|
sizeof(CO_CALL_PARAMETERS) +
|
|
FIELD_OFFSET(CO_CALL_MANAGER_PARAMETERS, CallMgrSpecific) +
|
|
FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters) +
|
|
TcObjAlignedLength +
|
|
FIELD_OFFSET(CO_MEDIA_PARAMETERS, MediaSpecific) +
|
|
FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters);
|
|
|
|
if(Adapter->MediaType == NdisMediumWan) {
|
|
|
|
CallParamsLength += sizeof(QOS_WAN_MEDIA);
|
|
}
|
|
|
|
PsAllocatePool( CallParams, CallParamsLength, CmParamsTag );
|
|
|
|
if ( CallParams == NULL ) {
|
|
|
|
PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
|
|
("[QosModifyCfInfoNotify]: Adapter %08X, can't allocate call params\n"));
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Create a call parameters struct for the ModifyCallQoS
|
|
//
|
|
|
|
CallMgrParams = (PCO_CALL_MANAGER_PARAMETERS)(CallParams + 1);
|
|
CallMgrParams->Transmit = NewCfInfo->GenFlow.SendingFlowspec;
|
|
CallMgrParams->Receive = NewCfInfo->GenFlow.ReceivingFlowspec;
|
|
CallMgrParams->CallMgrSpecific.ParamType = PARAM_TYPE_GQOS_INFO;
|
|
CallMgrParams->CallMgrSpecific.Length = NewCfInfo->GenFlow.TcObjectsLength;
|
|
|
|
if (NewCfInfo->GenFlow.TcObjectsLength > 0) {
|
|
NdisMoveMemory(
|
|
CallMgrParams->CallMgrSpecific.Parameters,
|
|
NewCfInfo->GenFlow.TcObjects,
|
|
NewCfInfo->GenFlow.TcObjectsLength);
|
|
}
|
|
|
|
// Ndis requires at least 8 bytes of media specific! Use dummy.
|
|
|
|
PsMediaParameters =
|
|
(PCO_MEDIA_PARAMETERS)((PUCHAR)CallMgrParams +
|
|
FIELD_OFFSET(CO_CALL_MANAGER_PARAMETERS, CallMgrSpecific) +
|
|
FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters) +
|
|
TcObjAlignedLength);
|
|
|
|
PsMediaParameters->Flags = 0;
|
|
PsMediaParameters->ReceivePriority = 0;
|
|
PsMediaParameters->ReceiveSizeHint = NewCfInfo->GenFlow.SendingFlowspec.MaxSduSize;
|
|
PsMediaParameters->MediaSpecific.ParamType = PARAM_TYPE_GQOS_INFO;
|
|
PsMediaParameters->MediaSpecific.Length = 0;
|
|
|
|
if(Adapter->MediaType == NdisMediumWan) {
|
|
|
|
LPQOS_WAN_MEDIA WanMedia;
|
|
PsMediaParameters->MediaSpecific.Length += sizeof(QOS_WAN_MEDIA);
|
|
WanMedia = (LPQOS_WAN_MEDIA) PsMediaParameters->MediaSpecific.Parameters;
|
|
|
|
WanMedia->ObjectHdr.ObjectType = QOS_OBJECT_WAN_MEDIA;
|
|
WanMedia->ObjectHdr.ObjectLength = sizeof(QOS_WAN_MEDIA);
|
|
|
|
NdisMoveMemory(&WanMedia->LinkId,
|
|
GpcClientVc->WanLink->OriginalRemoteMacAddress,
|
|
6);
|
|
|
|
}
|
|
|
|
CallParams->Flags = 0;
|
|
CallParams->CallMgrParameters = CallMgrParams;
|
|
CallParams->MediaParameters = (PCO_MEDIA_PARAMETERS)PsMediaParameters;
|
|
|
|
GpcClientVc->ModifyCallParameters = CallParams;
|
|
GpcClientVc->ModifyCfInfoQoS = NewCfInfo;
|
|
|
|
PS_LOCK(&GpcClientVc->Lock);
|
|
|
|
switch(GpcClientVc->ClVcState) {
|
|
|
|
case CL_INTERNAL_CALL_COMPLETE:
|
|
|
|
// CL_INTERNAL_CALL_COMPLETE:
|
|
// If we are in this state, then probably we have
|
|
// told the GPC about the Add, & the GPC has turned right
|
|
// back and asked us to modify before we have got a chance
|
|
// to transistion to CL_CALL_COMPLETE.
|
|
|
|
//
|
|
// Remember that we have got a modify, we will complete the modify
|
|
// when we transistion to the CL_CALL_COMPLETE state.
|
|
//
|
|
|
|
GpcClientVc->Flags |= GPC_MODIFY_REQUESTED;
|
|
PS_UNLOCK(&GpcClientVc->Lock);
|
|
#if DBG
|
|
NdisInterlockedIncrement(&Adapter->GpcNotifyPending);
|
|
#endif
|
|
return NDIS_STATUS_PENDING;
|
|
|
|
case CL_CALL_COMPLETE:
|
|
|
|
GpcClientVc->ClVcState = CL_MODIFY_PENDING;
|
|
PS_UNLOCK(&GpcClientVc->Lock);
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// In general, we expect the call to be in the
|
|
// CL_CALL_COMPLETE state when a modify request comes
|
|
// in. It could be in the following states as well:
|
|
//
|
|
// CALL_PENDING:
|
|
// If we are in this state, then we have not
|
|
// completed the AddCfInfo request from the GPC. This
|
|
// should not happen.
|
|
//
|
|
//
|
|
// GPC_CLOSE_PENDING:
|
|
// If an InternalCloseCall is requested, we
|
|
// change to this state before asking the GPC to
|
|
// close. The GPC could slip in this window and
|
|
// ask us to modify the call.
|
|
//
|
|
// MODIFY_PENDING:
|
|
// We have not told the GPC about the previous modify
|
|
// request. Therefore, the GPC cannot ask us to modify a
|
|
// call if we are in this state.
|
|
//
|
|
|
|
PsAssert(GpcClientVc->ClVcState != CL_CALL_PENDING);
|
|
PsAssert(GpcClientVc->ClVcState != CL_MODIFY_PENDING);
|
|
PsAssert(GpcClientVc->ClVcState != CL_GPC_CLOSE_PENDING);
|
|
PS_UNLOCK(&GpcClientVc->Lock);
|
|
|
|
PsFreePool(CallParams);
|
|
GpcClientVc->ModifyCallParameters = 0;
|
|
GpcClientVc->ModifyCfInfoQoS = 0;
|
|
|
|
PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
|
|
("[QosModifyCfInfoNotify]: Adapter %08X, Vc %08X, State %08X, Flags %08X -"
|
|
" Not ready to modify flow !\n",
|
|
Adapter, GpcClientVc, GpcClientVc->ClVcState, GpcClientVc->Flags));
|
|
|
|
return(GPC_STATUS_NOTREADY);
|
|
}
|
|
|
|
//
|
|
// Now issue the ModifyCallQoS to the PS call manager
|
|
//
|
|
|
|
Status = CmModifyCall(GpcClientVc);
|
|
|
|
if(Status != NDIS_STATUS_PENDING) {
|
|
|
|
CmModifyCallComplete(Status, GpcClientVc, CallParams);
|
|
}
|
|
|
|
PsDbgOut(DBG_TRACE, DBG_GPC_QOS,
|
|
("[QosModifyCfInfoNotify]: Adapter %08X, Vc %08X, State %08X, Flags %08X -"
|
|
" modify flow returns pending \n",
|
|
Adapter, GpcClientVc, GpcClientVc->ClVcState, GpcClientVc->Flags));
|
|
|
|
#if DBG
|
|
NdisInterlockedIncrement(&Adapter->GpcNotifyPending);
|
|
#endif
|
|
return NDIS_STATUS_PENDING;
|
|
|
|
} // QosModifyCfInfoNotify
|
|
|
|
|
|
VOID
|
|
CmModifyCallComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN PGPC_CLIENT_VC GpcClientVc,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The call manager has finished processing a ModifyCallQoS request.
|
|
|
|
Arguments:
|
|
|
|
See the DDK
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PADAPTER Adapter = GpcClientVc->Adapter;
|
|
|
|
//
|
|
// We call this to change back to the CALL_COMPLETE state.
|
|
// We make the same call whether the modify actually completed
|
|
// or not, since the call remains up.
|
|
//
|
|
// The internal best effort VC is not known by
|
|
// the GPC and therefore, is never modified by it.
|
|
//
|
|
|
|
PsAssert(!IsBestEffortVc(GpcClientVc));
|
|
|
|
|
|
if(Status != NDIS_STATUS_SUCCESS){
|
|
|
|
PsDbgOut(DBG_FAILURE,
|
|
DBG_GPC_QOS,
|
|
("[CmModifyCallQoSComplete]: Adapter %08X, Vc %08x, modify QoS failed. Status = %x\n",
|
|
Adapter, GpcClientVc, Status));
|
|
|
|
PsFreePool(GpcClientVc->ModifyCallParameters);
|
|
|
|
InterlockedIncrement(&GpcClientVc->AdapterStats->FlowModsRejected);
|
|
|
|
//
|
|
// Transistion from CL_MODIFY_PENDING to CL_INTERNAL_CALL_COMPLETE
|
|
//
|
|
CallSucceededStateTransition(GpcClientVc);
|
|
}
|
|
else
|
|
{
|
|
PsDbgOut(DBG_TRACE,
|
|
DBG_GPC_QOS,
|
|
("[CmModifyCallQoSComplete]: Adapter %08X, Vc %08X, modify QoS succeeded. \n",
|
|
Adapter, GpcClientVc));
|
|
|
|
//
|
|
// Tell NDISWAN about the fragment size
|
|
//
|
|
if((Adapter->MediaType == NdisMediumWan) && (GpcClientVc->Flags & GPC_ISSLOW_FLOW))
|
|
{
|
|
MakeLocalNdisRequest(Adapter,
|
|
GpcClientVc->NdisWanVcHandle,
|
|
NdisRequestLocalSetInfo,
|
|
OID_QOS_ISSLOW_FRAGMENT_SIZE,
|
|
&GpcClientVc->ISSLOWFragmentSize,
|
|
sizeof(ULONG),
|
|
NULL);
|
|
|
|
}
|
|
|
|
//
|
|
// Update Stats
|
|
//
|
|
InterlockedIncrement(&GpcClientVc->AdapterStats->FlowsModified);
|
|
|
|
PsFreePool(GpcClientVc->CallParameters);
|
|
|
|
GpcClientVc->CallParameters = CallParameters;
|
|
GpcClientVc->ModifyCallParameters = NULL;
|
|
GpcClientVc->CfInfoQoS = GpcClientVc->ModifyCfInfoQoS;
|
|
GpcClientVc->ModifyCfInfoQoS = 0;
|
|
|
|
//
|
|
// Transistion from CL_MODIFY_PENDING to CL_INTERNAL_CALL_COMPLETE
|
|
//
|
|
CallSucceededStateTransition(GpcClientVc);
|
|
|
|
//
|
|
// Mark the TOS Byte for this service type
|
|
//
|
|
PS_LOCK(&GpcClientVc->Lock);
|
|
|
|
SetTOSIEEEValues(GpcClientVc);
|
|
|
|
PS_UNLOCK(&GpcClientVc->Lock);
|
|
|
|
}
|
|
|
|
PsAssert(GpcEntries.GpcModifyCfInfoNotifyCompleteHandler);
|
|
|
|
GpcEntries.GpcModifyCfInfoNotifyCompleteHandler(GpcQosClientHandle,
|
|
GpcClientVc->CfInfoHandle,
|
|
Status);
|
|
//
|
|
// Transistion from CL_INTERNAL_CALL_COMPLETE to CL_CALL_COMPLETE
|
|
//
|
|
CallSucceededStateTransition(GpcClientVc);
|
|
|
|
#if DBG
|
|
NdisInterlockedDecrement(&Adapter->GpcNotifyPending);
|
|
#endif
|
|
|
|
} // ClModifyCallQoSComplete
|
|
|
|
|
|
VOID
|
|
QosModifyCfInfoComplete(
|
|
IN GPC_CLIENT_HANDLE ClientContext,
|
|
IN GPC_CLIENT_HANDLE ClientCfInfoContext,
|
|
IN GPC_STATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The GPC has completed processing an AddCfInfo request.
|
|
|
|
Arguments:
|
|
|
|
ClientContext - Client context supplied to GpcRegisterClient
|
|
ClientCfInfoContext - CfInfo context
|
|
Status - Final status
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
} // QosModifyCfInfoComplete
|
|
|
|
|
|
GPC_STATUS
|
|
QosRemoveCfInfoNotify(
|
|
IN GPC_CLIENT_HANDLE ClientContext,
|
|
IN GPC_CLIENT_HANDLE ClientCfInfoContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A CF_INFO is being removed.
|
|
|
|
Arguments:
|
|
|
|
ClientContext - Client context supplied to GpcRegisterClient
|
|
ClientCfInfoContext - CfInfo context
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
|
|
{
|
|
PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC)ClientCfInfoContext;
|
|
NDIS_STATUS Status;
|
|
ULONG CurrentFlows;
|
|
PADAPTER Adapter = Vc->Adapter;
|
|
|
|
PsAssert(!IsBestEffortVc(Vc));
|
|
|
|
PsDbgOut(DBG_TRACE, DBG_GPC_QOS,
|
|
("[QosRemoveCfInfoNotify]: Adapter %08X, Vc %08X, State %08X,"
|
|
"Flags %08X \n", Adapter, Vc, Vc->ClVcState, Vc->Flags));
|
|
|
|
//
|
|
// Check the state of the VC.
|
|
//
|
|
|
|
PS_LOCK(&Vc->Lock);
|
|
|
|
switch(Vc->ClVcState){
|
|
|
|
case CL_CALL_PENDING:
|
|
case CL_MODIFY_PENDING:
|
|
|
|
|
|
// CL_NDIS_CLOSE_PENDING:
|
|
//
|
|
// The GPC has to close before Ndis closes. So - if we're here, the GPC has already
|
|
// closed, in which case - it should not be trying to close again.
|
|
//
|
|
// CL_CALL_PENDING, CL_MODIFY_PENDING:
|
|
//
|
|
// The GPC is asking us to close a VC which we never told it about. Note that even
|
|
// though we can change from CL_INTERNAL_CALL_COMPLETE to CL_MODIFY_PENDING,
|
|
// the GPC can *never* ask us to close in CL_MODIFY_PENDING because
|
|
// even if the above case happens, we have not completed the modify with the GPC.
|
|
//
|
|
|
|
PS_UNLOCK(&Vc->Lock);
|
|
|
|
PsDbgOut(DBG_FAILURE,
|
|
DBG_STATE,
|
|
("[QosRemoveCfInfoNotify]: bad state %s on VC %x\n",
|
|
GpcVcState[Vc->ClVcState], Vc));
|
|
|
|
PsAssert(0);
|
|
|
|
return(GPC_STATUS_FAILURE);
|
|
|
|
case CL_INTERNAL_CALL_COMPLETE:
|
|
|
|
//
|
|
// We tell the GPC in the CL_INTERNAL_CALL_COMPLETE state and then transistion
|
|
// to the CL_CALL_COMPLETE state. However, there is a small window when the GPC
|
|
// can ask us to delete this VC in the CL_INTERNAL_CALL_COMPLETE state
|
|
// We wait till we move to CL_CALL_COMPLETE before deleting the Vc.
|
|
//
|
|
|
|
Vc->Flags |= GPC_CLOSE_REQUESTED;
|
|
|
|
PS_UNLOCK(&Vc->Lock);
|
|
|
|
#if DBG
|
|
NdisInterlockedIncrement(&Adapter->GpcNotifyPending);
|
|
#endif
|
|
|
|
return (GPC_STATUS_PENDING);
|
|
|
|
case CL_CALL_COMPLETE:
|
|
|
|
//
|
|
// Normal GPC close request.
|
|
//
|
|
|
|
Vc->ClVcState = CL_GPC_CLOSE_PENDING;
|
|
|
|
Vc->Flags |= GPC_CLOSE_REQUESTED;
|
|
|
|
PS_UNLOCK(&Vc->Lock);
|
|
|
|
Status = CmCloseCall(Vc);
|
|
|
|
PsAssert(Status == NDIS_STATUS_PENDING);
|
|
|
|
#if DBG
|
|
NdisInterlockedIncrement(&Adapter->GpcNotifyPending);
|
|
#endif
|
|
|
|
return(GPC_STATUS_PENDING);
|
|
|
|
case CL_INTERNAL_CLOSE_PENDING:
|
|
|
|
//
|
|
// We're here cause we were about to initiate a close and we're waiting
|
|
// for it to complete. It looks like the GPC asked us to close, before
|
|
// we actually asked it to close. First - check that the GPC has not
|
|
// asked us to close prior to this request.
|
|
//
|
|
|
|
PsAssert(!(Vc->Flags & GPC_CLOSE_REQUESTED));
|
|
|
|
//
|
|
// If the GPC is asking us to close, the GPC MUST fail the call when we
|
|
// ask it to close. So, we'll simply wait here till that happens. Note that
|
|
// we cannot pend this call and complete it later from the Internal Close handler.
|
|
//
|
|
// If we Deref the VC from the Internal Close Complete handler, there could be a race
|
|
// condition and we could be looking at a stale VC pointer. So, the VC MUST be Deref'd
|
|
// from here. We do not have to call CmCloseCall because we called it from the InternalClose
|
|
// handler.
|
|
//
|
|
|
|
Vc->Flags |= GPC_CLOSE_REQUESTED;
|
|
|
|
PS_UNLOCK(&Vc->Lock);
|
|
|
|
NdisWaitEvent(&Vc->GpcEvent, 0);
|
|
|
|
DerefClVc(Vc);
|
|
|
|
return GPC_STATUS_SUCCESS;
|
|
|
|
default:
|
|
|
|
PS_UNLOCK(&Vc->Lock);
|
|
|
|
PsDbgOut(DBG_FAILURE,
|
|
DBG_STATE,
|
|
("[QosRemoveCfInfoNotify]: invalid state %s on VC %x\n",
|
|
GpcVcState[Vc->ClVcState], Vc));
|
|
|
|
PsAssert(0);
|
|
|
|
return GPC_STATUS_FAILURE;
|
|
}
|
|
|
|
} // QosRemoveCfInfoNotify
|
|
|
|
|
|
|
|
VOID
|
|
CmCloseCallComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN PGPC_CLIENT_VC Vc
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The call manager has finished processing a CloseCall request.
|
|
|
|
Arguments:
|
|
|
|
See the DDK
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PADAPTER Adapter = Vc->Adapter;
|
|
NDIS_STATUS LocalStatus;
|
|
ULONG CurrentFlows;
|
|
|
|
PsAssert(!IsBestEffortVc(Vc));
|
|
|
|
|
|
if(Adapter->MediaType == NdisMediumWan) {
|
|
|
|
//
|
|
// To optimize send path
|
|
//
|
|
InterlockedDecrement(&Vc->WanLink->CfInfosInstalled);
|
|
|
|
PS_LOCK(&Vc->WanLink->Lock);
|
|
|
|
Vc->WanLink->FlowsInstalled --;
|
|
|
|
CurrentFlows = Vc->WanLink->FlowsInstalled;
|
|
|
|
PS_UNLOCK(&Vc->WanLink->Lock);
|
|
|
|
PsTcNotify(Adapter, Vc->WanLink, OID_QOS_FLOW_COUNT, &CurrentFlows, sizeof(ULONG));
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// To optimize send path
|
|
//
|
|
InterlockedDecrement(&Adapter->CfInfosInstalled);
|
|
|
|
PS_LOCK(&Adapter->Lock);
|
|
|
|
Adapter->FlowsInstalled --;
|
|
|
|
CurrentFlows = Adapter->FlowsInstalled;
|
|
|
|
PS_UNLOCK(&Adapter->Lock);
|
|
|
|
PsTcNotify(Adapter, 0, OID_QOS_FLOW_COUNT, &CurrentFlows, sizeof(ULONG));
|
|
}
|
|
|
|
//
|
|
// Update stats
|
|
//
|
|
|
|
InterlockedIncrement(&Vc->AdapterStats->FlowsClosed);
|
|
|
|
Vc->AdapterStats->MaxSimultaneousFlows =
|
|
max(Vc->AdapterStats->MaxSimultaneousFlows, CurrentFlows);
|
|
|
|
PS_LOCK(&Vc->Lock);
|
|
|
|
if(Vc->Flags & INTERNAL_CLOSE_REQUESTED)
|
|
{
|
|
// We have asked to close this call. Let's process the close now.
|
|
// Note that we don't really care if the GPC has asked us to close.
|
|
//
|
|
// Because -
|
|
// 1. If we had initiated an internal close after the GPC asks us to close, we ignore the internal close,
|
|
// and the above flag will not be set.
|
|
// 2. If the GPC had asked us to close, we have pended it - We will now complete it when the GPC fails our
|
|
// call to close the Vc.
|
|
//
|
|
|
|
PS_UNLOCK(&Vc->Lock);
|
|
|
|
PsDbgOut(DBG_TRACE, DBG_GPC_QOS,
|
|
("[CmCloseCallComplete]: Adapter %08X, Vc %08X (State %08X, Flags %08X), "
|
|
"Internal Close requested \n",
|
|
Adapter, Vc, Vc->ClVcState, Vc->Flags));
|
|
|
|
Status = GpcEntries.GpcRemoveCfInfoHandler(GpcQosClientHandle, Vc->CfInfoHandle);
|
|
|
|
if(Status != NDIS_STATUS_PENDING) {
|
|
|
|
QosRemoveCfInfoComplete(NULL, Vc, Status);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
PS_UNLOCK(&Vc->Lock);
|
|
|
|
//
|
|
// Complete the request with the GPC.
|
|
//
|
|
GpcEntries.GpcRemoveCfInfoNotifyCompleteHandler(GpcQosClientHandle,
|
|
Vc->CfInfoHandle,
|
|
GPC_STATUS_SUCCESS);
|
|
|
|
#if DBG
|
|
NdisInterlockedDecrement(&Adapter->GpcNotifyPending);
|
|
#endif
|
|
DerefClVc(Vc);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
DerefClVc(
|
|
PGPC_CLIENT_VC Vc
|
|
)
|
|
{
|
|
ULONG RefCount;
|
|
|
|
RefCount = InterlockedDecrement(&Vc->RefCount);
|
|
|
|
if(!RefCount)
|
|
{
|
|
PsDbgOut(DBG_INFO,
|
|
DBG_STATE,
|
|
("DerefClVc: deref'd to 0. State is %s on VC %x\n",
|
|
GpcVcState[Vc->ClVcState], Vc));
|
|
|
|
if(Vc->NdisWanVcHandle)
|
|
{
|
|
WanCloseCall(Vc);
|
|
}
|
|
else
|
|
{
|
|
CmDeleteVc(Vc);
|
|
}
|
|
|
|
}
|
|
|
|
} // DerefClVc
|
|
|
|
|
|
|
|
VOID
|
|
QosRemoveCfInfoComplete(
|
|
IN GPC_CLIENT_HANDLE ClientContext,
|
|
IN GPC_CLIENT_HANDLE ClientCfInfoContext,
|
|
IN GPC_STATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The GPC has completed processing an AddCfInfo request.
|
|
|
|
Arguments:
|
|
|
|
ClientContext - Client context supplied to GpcRegisterClient
|
|
ClientCfInfoContext - CfInfo context
|
|
Status - Final status
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC)ClientCfInfoContext;
|
|
|
|
PsDbgOut(DBG_TRACE, DBG_GPC_QOS,
|
|
("[QosRemoveCfInfoComplete]: Adapter %08X, Vc %08X "
|
|
"(State = %08X, Flags = %08X), Status %08X \n", Vc->Adapter, Vc,
|
|
Vc->ClVcState, Vc->Flags, Status));
|
|
|
|
if(Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// The GPC has requested a close, which has been pended. Complete that request.
|
|
//
|
|
|
|
PsDbgOut(DBG_TRACE,
|
|
DBG_GPC_QOS,
|
|
("[QosRemoveCfInfoComplete]: Vc %08X, completing with GPC \n", Vc));
|
|
|
|
NdisSetEvent(&Vc->GpcEvent);
|
|
}
|
|
else {
|
|
DerefClVc(Vc);
|
|
}
|
|
|
|
} // QosRemoveCfInfoComplete
|
|
|