Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

792 lines
18 KiB

/*++
Copyright (c) 1999, Microsoft Corporation
Module Name:
qosminfo.c
Abstract:
The file contains global and interface
config functions for QOS Mgr protocol.
Revision History:
--*/
#include "pchqosm.h"
#pragma hdrstop
DWORD
WINAPI
QosmGetGlobalInfo (
IN PVOID GlobalInfo,
IN OUT PULONG BufferSize,
OUT PULONG InfoSize
)
/*++
Routine Description:
Returns the global config info for this protocol.
Arguments:
See corr header file.
Return Value:
Status of the operation
--*/
{
PIPQOS_GLOBAL_CONFIG GlobalConfig;
DWORD Status;
//
// Validate all input params before reading the global info
//
if (BufferSize == NULL)
{
return ERROR_INVALID_PARAMETER;
}
ACQUIRE_GLOBALS_READ_LOCK();
do
{
*InfoSize = Globals.ConfigSize;
if ((*BufferSize < *InfoSize) ||
(GlobalInfo == NULL))
{
//
// Either the size was too small or there was no storage
//
Trace1(CONFIG,
"GetGlobalInfo: Buffer size too small: %u",
*BufferSize);
*BufferSize = *InfoSize;
Status = ERROR_INSUFFICIENT_BUFFER;
break;
}
*BufferSize = *InfoSize;
GlobalConfig = (PIPQOS_GLOBAL_CONFIG) GlobalInfo;
CopyMemory(GlobalConfig,
Globals.GlobalConfig,
*InfoSize);
Status = NO_ERROR;
}
while (FALSE);
RELEASE_GLOBALS_READ_LOCK();
return Status;
}
DWORD
WINAPI
QosmSetGlobalInfo (
IN PVOID GlobalInfo,
IN ULONG InfoSize
)
/*++
Routine Description:
Sets the global config info for this protocol.
Arguments:
See corr header file.
Return Value:
Status of the operation
--*/
{
PIPQOS_GLOBAL_CONFIG GlobalConfig;
DWORD Status;
//
// Update the global config information.
//
ACQUIRE_GLOBALS_WRITE_LOCK();
do
{
GlobalConfig = AllocMemory(InfoSize);
if (GlobalConfig == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
break;
}
//
// Copy the new config information
//
CopyMemory(GlobalConfig, GlobalInfo, InfoSize);
Globals.ConfigSize = InfoSize;
//
// Set up rest of the global state
//
if (GlobalConfig->LoggingLevel <= IPQOS_LOGGING_INFO)
{
Globals.LoggingLevel = GlobalConfig->LoggingLevel;
}
//
// Cleanup old global information
//
if (Globals.GlobalConfig)
{
FreeMemory(Globals.GlobalConfig);
}
Globals.GlobalConfig = GlobalConfig;
Status = NO_ERROR;
}
while (FALSE);
RELEASE_GLOBALS_WRITE_LOCK();
return Status;
}
DWORD
WINAPI
QosmGetInterfaceInfo (
IN QOSMGR_INTERFACE_ENTRY *Interface,
IN PVOID InterfaceInfo,
IN OUT PULONG BufferSize,
OUT PULONG InfoSize
)
/*++
Routine Description:
Gets the inteface config info for this protocol
for this interface.
Arguments:
See corr header file.
Return Value:
Status of the operation
--*/
{
PIPQOS_IF_CONFIG InterfaceConfig;
DWORD Status;
//
// Validate all input params before reading interface info
//
if (BufferSize == NULL)
{
return ERROR_INVALID_PARAMETER;
}
ACQUIRE_INTERFACE_READ_LOCK(Interface);
do
{
*InfoSize = Interface->ConfigSize;
if ((*BufferSize < *InfoSize) ||
(InterfaceInfo == NULL))
{
//
// Either the size was too small or there was no storage
//
Trace1(CONFIG,
"GetInterfaceInfo: Buffer size too small: %u",
*BufferSize);
*BufferSize = *InfoSize;
Status = ERROR_INSUFFICIENT_BUFFER;
break;
}
*BufferSize = *InfoSize;
InterfaceConfig = (PIPQOS_IF_CONFIG) InterfaceInfo;
CopyMemory(InterfaceConfig,
Interface->InterfaceConfig,
*InfoSize);
Status = NO_ERROR;
}
while (FALSE);
RELEASE_INTERFACE_READ_LOCK(Interface);
return Status;
}
DWORD
WINAPI
QosmSetInterfaceInfo (
IN QOSMGR_INTERFACE_ENTRY *Interface,
IN PVOID InterfaceInfo,
IN ULONG InfoSize
)
/*++
Routine Description:
Sets the interface config info for this protocol
on this interface.
Arguments:
See corr header file.
Return Value:
Status of the operation
--*/
{
PIPQOS_IF_CONFIG InterfaceConfig;
PIPQOS_IF_FLOW FlowConfig;
PQOSMGR_FLOW_ENTRY Flow;
UINT i;
PLIST_ENTRY p, q;
PTC_GEN_FLOW FlowInfo;
ULONG FlowSize;
HANDLE FlowHandle;
DWORD Status;
//
// Update the interface config information.
//
ACQUIRE_INTERFACE_WRITE_LOCK(Interface);
do
{
//
// Allocate memory to store new config
//
InterfaceConfig = AllocMemory(InfoSize);
if (InterfaceConfig == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
break;
}
//
// Copy the new config information
//
CopyMemory(InterfaceConfig, InterfaceInfo, InfoSize);
Interface->ConfigSize = InfoSize;
//
// Set up rest of interface state
//
if (Interface->State != InterfaceConfig->QosState)
{
if (InterfaceConfig->QosState == IPQOS_STATE_DISABLED)
{
//
// Disable all flows on this interface
//
;
}
else
{
//
// Renable all flows on this interface
//
;
}
Interface->State = InterfaceConfig->QosState;
}
//
// Update the flow information on if
//
//
// First mark all flows as needing refresh
//
for (p = Interface->FlowList.Flink;
p != &Interface->FlowList;
p = p->Flink)
{
Flow = CONTAINING_RECORD(p, QOSMGR_FLOW_ENTRY, OnInterfaceLE);
ASSERT(!(Flow->Flags & FLOW_FLAG_DELETE));
Flow->Flags |= FLOW_FLAG_DELETE;
}
//
// If we do not have an TC interface handle,
// we delete all flows as they are obsolete
//
if (Interface->TciIfHandle)
{
//
// Set each flow if it has changed from before
//
FlowConfig = IPQOS_GET_FIRST_FLOW_ON_IF(InterfaceConfig);
for (i = 0; i < InterfaceConfig->NumFlows; i++)
{
//
// Search for a flow with the same name
//
for (p = Interface->FlowList.Flink;
p != &Interface->FlowList;
p = p->Flink)
{
Flow =
CONTAINING_RECORD(p, QOSMGR_FLOW_ENTRY, OnInterfaceLE);
if (!_wcsicmp(Flow->FlowName, FlowConfig->FlowName))
{
break;
}
}
if (p == &Interface->FlowList)
{
//
// No flow by this name - add new one
//
Flow = NULL;
}
//
// Get a flow info from description
//
Status = GetFlowFromDescription(&FlowConfig->FlowDesc,
&FlowInfo,
&FlowSize);
if (Status == NO_ERROR)
{
do
{
if ((Flow) &&
(FlowSize == Flow->FlowSize) &&
(EqualMemory(FlowInfo, Flow->FlowInfo, FlowSize)))
{
//
// No change in the flow info yet,
// this flow still remains valid
//
Flow->Flags &= ~FLOW_FLAG_DELETE;
Status = ERROR_ALREADY_EXISTS;
break;
}
if (Flow)
{
//
// Flow info changed - modify flow
//
Status = TcModifyFlow(Flow->TciFlowHandle,
FlowInfo);
if (Status != NO_ERROR)
{
break;
}
Flow->Flags &= ~FLOW_FLAG_DELETE;
//
// Update cached flow info
//
FreeMemory(Flow->FlowInfo);
Flow->FlowInfo = FlowInfo;
Flow->FlowSize = FlowSize;
}
else
{
//
// Add the new flow using the TC API
//
Status = TcAddFlow(Interface->TciIfHandle,
NULL,
0,
FlowInfo,
&FlowHandle);
if (Status != NO_ERROR)
{
break;
}
//
// Addition of a new flow in TC
//
Flow = AllocMemory(sizeof(QOSMGR_FLOW_ENTRY));
if (Flow == NULL)
{
Status = TcDeleteFlow(FlowHandle);
ASSERT(Status);
Status = ERROR_NOT_ENOUGH_MEMORY;
break;
}
//
// Initialize flow and insert in list
//
Flow->TciFlowHandle = FlowHandle;
Flow->Flags = 0;
Flow->FlowInfo = FlowInfo;
Flow->FlowSize = FlowSize;
wcscpy(Flow->FlowName, FlowConfig->FlowName);
InsertTailList(p, &Flow->OnInterfaceLE);
}
}
while (FALSE);
if (Status != NO_ERROR)
{
FreeMemory(FlowInfo);
}
}
//
// Move to the next flow in config
//
FlowConfig = IPQOS_GET_NEXT_FLOW_ON_IF(FlowConfig);
}
}
//
// Cleanup all flows that are obsolete
//
for (p = Interface->FlowList.Flink;
p != &Interface->FlowList;
p = q)
{
Flow = CONTAINING_RECORD(p, QOSMGR_FLOW_ENTRY, OnInterfaceLE);
q = p->Flink;
if (Flow->Flags & FLOW_FLAG_DELETE)
{
//
// Delete the flow from the TC API
//
Status = TcDeleteFlow(Flow->TciFlowHandle);
if (Status != NO_ERROR)
{
Flow->Flags &= ~FLOW_FLAG_DELETE;
continue;
}
//
// Remove flow from this flow list
//
RemoveEntryList(p);
//
// Free the flow and its resources
//
if (Flow->FlowInfo)
{
FreeMemory(Flow->FlowInfo);
}
FreeMemory(Flow);
}
}
//
// Cleanup old interface information
//
if (Interface->InterfaceConfig)
{
FreeMemory(Interface->InterfaceConfig);
}
Interface->InterfaceConfig = InterfaceConfig;
Status = NO_ERROR;
}
while (FALSE);
RELEASE_INTERFACE_WRITE_LOCK(Interface);
return Status;
}
DWORD
GetFlowFromDescription(
IN PIPQOS_NAMED_FLOW FlowDesc,
OUT PTC_GEN_FLOW *FlowInfo,
OUT ULONG *FlowSize
)
{
FLOWSPEC *CurrFlowspec;
FLOWSPEC SendFlowspec;
FLOWSPEC RecvFlowspec;
FLOWSPEC *Flowspec;
PTC_GEN_FLOW Flow;
QOS_OBJECT_HDR *QosObject;
PWCHAR FlowspecName;
PWCHAR QosObjectName;
PUCHAR CopyAtPtr;
ULONG ObjectsLength;
ULONG i;
#if 1
//
// Check for the existence of sending flowspec
//
if (FlowDesc->SendingFlowspecName[0] == L'\0')
{
return ERROR_INVALID_DATA;
}
#endif
//
// Get the sending and receiving flowspecs
//
for (i = 0; i < 2; i++)
{
if (i)
{
FlowspecName = FlowDesc->RecvingFlowspecName;
CurrFlowspec = &RecvFlowspec;
}
else
{
FlowspecName = FlowDesc->SendingFlowspecName;
CurrFlowspec = &SendFlowspec;
}
FillMemory(CurrFlowspec, sizeof(FLOWSPEC), QOS_NOT_SPECIFIED);
if (FlowspecName[0] != L'\0')
{
Flowspec = GetFlowspecFromGlobalConfig(FlowspecName);
if (Flowspec == NULL)
{
return ERROR_INVALID_DATA;
}
*CurrFlowspec = *Flowspec;
}
}
//
// Calculate the size of the TC_GEN_FLOW block
//
QosObjectName = IPQOS_GET_FIRST_OBJECT_NAME_ON_NAMED_FLOW(FlowDesc);
ObjectsLength = 0;
for (i = 0; i < FlowDesc->NumTcObjects; i++)
{
//
// Get object's description in global info
//
QosObject = GetQosObjectFromGlobalConfig(QosObjectName);
if (QosObject == NULL)
{
//
// Incomplete description
//
return ERROR_INVALID_DATA;
}
ObjectsLength += QosObject->ObjectLength;
QosObjectName= IPQOS_GET_NEXT_OBJECT_NAME_ON_NAMED_FLOW(QosObjectName);
}
*FlowSize = FIELD_OFFSET(TC_GEN_FLOW, TcObjects) + ObjectsLength;
*FlowInfo = Flow = AllocMemory(*FlowSize);
if (Flow == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Fill in the flow information now
//
Flow->ReceivingFlowspec = RecvFlowspec;
Flow->SendingFlowspec = SendFlowspec;
Flow->TcObjectsLength = ObjectsLength;
//
// Repeat the loop above filling info
//
QosObjectName = IPQOS_GET_FIRST_OBJECT_NAME_ON_NAMED_FLOW(FlowDesc);
CopyAtPtr = (PUCHAR) &Flow->TcObjects[0];
for (i = 0; i < FlowDesc->NumTcObjects; i++)
{
//
// Get object's description in global info
//
QosObject = GetQosObjectFromGlobalConfig(QosObjectName);
// We just checked above for its existence
ASSERT(QosObject != NULL);
CopyMemory(CopyAtPtr,
QosObject,
QosObject->ObjectLength);
CopyAtPtr += QosObject->ObjectLength;
QosObjectName= IPQOS_GET_NEXT_OBJECT_NAME_ON_NAMED_FLOW(QosObjectName);
}
return NO_ERROR;
}
FLOWSPEC *
GetFlowspecFromGlobalConfig(
IN PWCHAR FlowspecName
)
{
IPQOS_NAMED_FLOWSPEC *Flowspec;
UINT i;
Flowspec = IPQOS_GET_FIRST_FLOWSPEC_IN_CONFIG(Globals.GlobalConfig);
for (i = 0; i < Globals.GlobalConfig->NumFlowspecs; i++)
{
if (!_wcsicmp(Flowspec->FlowspecName, FlowspecName))
{
break;
}
Flowspec = IPQOS_GET_NEXT_FLOWSPEC_IN_CONFIG(Flowspec);
}
if (i < Globals.GlobalConfig->NumFlowspecs)
{
return &Flowspec->FlowspecDesc;
}
return NULL;
}
QOS_OBJECT_HDR *
GetQosObjectFromGlobalConfig(
IN PWCHAR QosObjectName
)
{
IPQOS_NAMED_QOSOBJECT *QosObject;
UINT i;
QosObject = IPQOS_GET_FIRST_QOSOBJECT_IN_CONFIG(Globals.GlobalConfig);
for (i = 0; i < Globals.GlobalConfig->NumQosObjects; i++)
{
if (!_wcsicmp(QosObject->QosObjectName, QosObjectName))
{
break;
}
QosObject = IPQOS_GET_NEXT_QOSOBJECT_IN_CONFIG(QosObject);
}
if (i < Globals.GlobalConfig->NumFlowspecs)
{
return &QosObject->QosObjectHdr;
}
return NULL;
}