1699 lines
45 KiB
C
1699 lines
45 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1995 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
net\routing\ipx\sap\routerif.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
SAP interface with router (APIs for protocol dll under
|
||
|
NT/Cairo router, SNMP MIB support, IPX Service Table Manager)
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Vadim Eydelman 05-15-1995
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
#include "sapp.h"
|
||
|
|
||
|
DWORD (WINAPI *MIBEntryGet)(
|
||
|
IN DWORD dwRoutingPid,
|
||
|
IN DWORD dwInEntrySize,
|
||
|
IN LPVOID lpInEntry,
|
||
|
IN OUT LPDWORD lpOutEntrySize,
|
||
|
OUT LPVOID lpOutEntry);
|
||
|
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
S T A R T _ P R O T O C O L _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Starts sap agent
|
||
|
Arguments:
|
||
|
NotificationEvent - this event will be used to notify router manager
|
||
|
of completion of lengthly operation
|
||
|
GlobalInfo - empty
|
||
|
Return Value:
|
||
|
NO_ERROR - SAP agent was started OK
|
||
|
ERROR_CAN_NOT_COMPLETE - operation can not be completed
|
||
|
ERROR_INVALID_PARAMETER - one or more parameters are invalid
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
StartProtocol(
|
||
|
IN HANDLE NotificationEvent,
|
||
|
IN PSUPPORT_FUNCTIONS SupportFunctions,
|
||
|
IN LPVOID GlobalInfo
|
||
|
) {
|
||
|
#define sapGlobalInfo ((PSAP_GLOBAL_INFO)GlobalInfo)
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (!RouterIfActive) {
|
||
|
RouterIfActive = TRUE;
|
||
|
EventLogMask = sapGlobalInfo->EventLogMask;
|
||
|
status = CreateResultQueue (NotificationEvent);
|
||
|
if (status==NO_ERROR) {
|
||
|
if (!ServiceIfActive) {
|
||
|
status = CreateAllComponents (NotificationEvent);
|
||
|
if (status==NO_ERROR) {
|
||
|
status = StartSAP ();
|
||
|
if (status==NO_ERROR) {
|
||
|
MIBEntryGet = SupportFunctions->MIBEntryGet;
|
||
|
status = NO_ERROR;
|
||
|
goto Success;
|
||
|
}
|
||
|
DeleteAllComponents ();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
StopInterfaces ();
|
||
|
StopSAP ();
|
||
|
MIBEntryGet = SupportFunctions->MIBEntryGet;
|
||
|
goto Success;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
RouterIfActive = FALSE;
|
||
|
}
|
||
|
else {
|
||
|
Trace (DEBUG_FAILURES, "File: %s, line %ld."
|
||
|
" SAP is already running.",
|
||
|
__FILE__, __LINE__);
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
|
||
|
Success:
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
#undef sapGlobalInfo
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
G E T _ G L O B A L _ I N F O _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Gets SAP global filter info
|
||
|
Arguments:
|
||
|
GlobalInfo - buffer to receive global info
|
||
|
GlobalInfoSize - on input: size of the buffer
|
||
|
on output: size of global info or size of the
|
||
|
required buffer if ERROR_INSUFFICIENT_BUFFER
|
||
|
is returned
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
ERROR_INSUFFICIENT_BUFFER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
|
||
|
DWORD WINAPI
|
||
|
GetGlobalInfo(
|
||
|
IN PVOID GlobalInfo,
|
||
|
IN OUT PULONG GlobalInfoSize
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
if ((*GlobalInfoSize>=sizeof (SAP_GLOBAL_INFO))
|
||
|
&& (GlobalInfo!=NULL)) {
|
||
|
#define sapGlobalInfo ((PSAP_GLOBAL_INFO)GlobalInfo)
|
||
|
sapGlobalInfo->EventLogMask = EventLogMask;
|
||
|
#undef sapGlobalInfo
|
||
|
}
|
||
|
*GlobalInfoSize = sizeof (SAP_GLOBAL_INFO);
|
||
|
status = NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
S E T _ G L O B A L _ I N F O _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Sets SAP global filter info
|
||
|
Arguments:
|
||
|
GlobalInfo - buffer with receive global info
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
SetGlobalInfo(
|
||
|
IN PVOID GlobalInfo
|
||
|
) {
|
||
|
#define sapGlobalInfo ((PSAP_GLOBAL_INFO)GlobalInfo)
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
EventLogMask = sapGlobalInfo->EventLogMask;
|
||
|
status = NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
#undef sapGlobalInfo
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
S T O P _ P R O T O C O L _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Shutdown SAP agent
|
||
|
Arguments:
|
||
|
None
|
||
|
Return Value:
|
||
|
NO_ERROR - SAP agent was stopped OK
|
||
|
ERROR_STOP_PENDING - for asynchronous completion.
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
StopProtocol(
|
||
|
void
|
||
|
) {
|
||
|
DWORD status;
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_STOPPING) {
|
||
|
Trace (DEBUG_FAILURES, "File: %s, line %ld."
|
||
|
" SAP is stopping already.",
|
||
|
__FILE__, __LINE__);
|
||
|
status = ERROR_PROTOCOL_STOP_PENDING;
|
||
|
}
|
||
|
|
||
|
else if (OperationalState==OPER_STATE_DOWN) {
|
||
|
Trace (DEBUG_FAILURES, "File: %s, line %ld."
|
||
|
" SAP already stopped or not started.",
|
||
|
__FILE__, __LINE__);
|
||
|
status = NO_ERROR;
|
||
|
}
|
||
|
else if (!RouterIfActive) {
|
||
|
Trace (DEBUG_FAILURES, "File: %s, line %ld."
|
||
|
" Router interface is not active.",
|
||
|
__FILE__, __LINE__);
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
else {
|
||
|
RouterIfActive = FALSE;
|
||
|
StopSAP ();
|
||
|
status = ERROR_PROTOCOL_STOP_PENDING;
|
||
|
}
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
G E T _ E V E N T _ M E S S A G E _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Dequeues message associated with completion of asynchronous
|
||
|
operation signalled by notification event
|
||
|
Arguments:
|
||
|
Event - buffer to store event id that produced this message
|
||
|
Result - buffer to store results specific to completed operation
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_NO_MORE_ITEMS - no more messages in the queue to report
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
GetEventMessage(
|
||
|
OUT ROUTING_PROTOCOL_EVENTS *Event,
|
||
|
OUT MESSAGE *Result
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if ((OperationalState==OPER_STATE_UP)
|
||
|
|| (OperationalState==OPER_STATE_STOPPING)
|
||
|
|| (OperationalState==OPER_STATE_STARTING)
|
||
|
)
|
||
|
status = SapGetEventResult (Event, Result);
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
A D D _ I N T E R F A C E _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Add interface to sap interface table
|
||
|
Arguments:
|
||
|
InterfaceIndex - unique number identifying interface to add
|
||
|
InterfacInfo - interface parameters
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
AddInterface(
|
||
|
IN LPWSTR InterfaceName,
|
||
|
IN ULONG InterfaceIndex,
|
||
|
IN NET_INTERFACE_TYPE InterfaceType,
|
||
|
IN PVOID InterfaceInfo
|
||
|
) {
|
||
|
#define sapInfo (&((PSAP_IF_CONFIG)InterfaceInfo)->SapIfInfo)
|
||
|
#define sapFilters (&((PSAP_IF_CONFIG)InterfaceInfo)->SapIfFilters)
|
||
|
DWORD status;
|
||
|
UNREFERENCED_PARAMETER(InterfaceType);
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
status = SapCreateSapInterface (
|
||
|
InterfaceName,
|
||
|
InterfaceIndex,
|
||
|
InterfaceType,
|
||
|
sapInfo);
|
||
|
if ((status==NO_ERROR)
|
||
|
&& ((sapFilters->SupplyFilterCount
|
||
|
+sapFilters->ListenFilterCount)>0))
|
||
|
status = SapSetInterfaceFilters (InterfaceIndex, sapFilters);
|
||
|
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
break;
|
||
|
case ERROR_ALREADY_EXISTS:
|
||
|
status = ERROR_INVALID_PARAMETER;
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
#undef sapIfInfo
|
||
|
#undef sapIfFilters
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
D E L E T E _ I N T E R F A C E _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Deletes interface from sap interface table and associated services
|
||
|
from sap service table
|
||
|
Arguments:
|
||
|
InterfaceIndex - unique number identifying interface to delete
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
DeleteInterface(
|
||
|
IN ULONG InterfaceIndex
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
status = SapDeleteSapInterface (InterfaceIndex);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
case ERROR_NO_MORE_ITEMS:
|
||
|
case ERROR_CAN_NOT_COMPLETE:
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
G E T _ I N T E R F A C E _ C O N F I G _ I N F O _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Gets interface configuration info from sap interface table
|
||
|
Arguments:
|
||
|
InterfaceIndex - unique index identifying interface to get info
|
||
|
InterfaceInfo - buffer to receive interface info
|
||
|
InterfaceInfoSize - on input: size of the buffer
|
||
|
on output: size of interface info or size of the
|
||
|
required buffer if ERROR_INSUFFICIENT_BUFFER
|
||
|
is returned
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
ERROR_INSUFFICIENT_BUFFER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
GetInterfaceConfigInfo(
|
||
|
IN ULONG InterfaceIndex,
|
||
|
IN PVOID InterfaceInfo,
|
||
|
IN OUT PULONG InterfaceInfoSize
|
||
|
) {
|
||
|
#define sapInfo (&((PSAP_IF_CONFIG)InterfaceInfo)->SapIfInfo)
|
||
|
#define sapFilters (&((PSAP_IF_CONFIG)InterfaceInfo)->SapIfFilters)
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
if (*InterfaceInfoSize>=sizeof(SAP_IF_INFO)) {
|
||
|
*InterfaceInfoSize -= sizeof (SAP_IF_INFO);
|
||
|
status = SapGetSapInterface (InterfaceIndex,
|
||
|
sapInfo,
|
||
|
NULL);
|
||
|
if (status==NO_ERROR)
|
||
|
status = SapGetInterfaceFilters (InterfaceIndex,
|
||
|
sapFilters,
|
||
|
InterfaceInfoSize);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
case ERROR_CAN_NOT_COMPLETE:
|
||
|
case ERROR_INSUFFICIENT_BUFFER:
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
*InterfaceInfoSize = 0;
|
||
|
status = SapGetInterfaceFilters (InterfaceIndex,
|
||
|
NULL, InterfaceInfoSize);
|
||
|
if (status==NO_ERROR)
|
||
|
status = ERROR_INSUFFICIENT_BUFFER;
|
||
|
}
|
||
|
*InterfaceInfoSize += sizeof (SAP_IF_INFO);
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
#undef sapIfInfo
|
||
|
#undef sapIfFilters
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
S E T _ I N T E R F A C E _ C O N F I G _ I N F O _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Sets interface configuration info in sap interface table
|
||
|
Arguments:
|
||
|
InterfaceIndex - unique index identifying interface to get info
|
||
|
InterfaceInfo - buffer with interface info
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
SetInterfaceConfigInfo(
|
||
|
IN ULONG InterfaceIndex,
|
||
|
IN PVOID InterfaceInfo
|
||
|
) {
|
||
|
#define sapInfo (&((PSAP_IF_CONFIG)InterfaceInfo)->SapIfInfo)
|
||
|
#define sapFilters (&((PSAP_IF_CONFIG)InterfaceInfo)->SapIfFilters)
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
status = SapSetSapInterface (InterfaceIndex, sapInfo);
|
||
|
if (status==NO_ERROR)
|
||
|
status = SapSetInterfaceFilters (InterfaceIndex, sapFilters);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
case ERROR_NO_MORE_ITEMS:
|
||
|
case ERROR_CAN_NOT_COMPLETE:
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
#undef sapIfInfo
|
||
|
#undef sapIfFilters
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
B I N D _ I N T E R F A C E _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Activates sap interface and binds it to the adapter
|
||
|
Start SAP if interface is configured for standart update mode
|
||
|
Arguments:
|
||
|
InterfaceIndex - unique index identifying interface to activate
|
||
|
BindingInfo - bound adpater info
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
BindInterface(
|
||
|
IN ULONG InterfaceIndex,
|
||
|
IN PVOID BindingInfo
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
status = SapBindSapInterfaceToAdapter (InterfaceIndex,
|
||
|
(PIPX_ADAPTER_BINDING_INFO)BindingInfo);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
case ERROR_NO_MORE_ITEMS:
|
||
|
case ERROR_CAN_NOT_COMPLETE:
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
U N B I N D _ I N T E R F A C E _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Deactivates sap interface and unbinds it to the adapter
|
||
|
Stops SAP on interface and deletes all services obtained
|
||
|
through SAP on this interface form the service table
|
||
|
Arguments:
|
||
|
InterfaceIndex - unique index identifying interface to deactivate
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
UnbindInterface(
|
||
|
IN ULONG InterfaceIndex
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
status = SapUnbindSapInterfaceFromAdapter (InterfaceIndex);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
case ERROR_NO_MORE_ITEMS:
|
||
|
case ERROR_CAN_NOT_COMPLETE:
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
E N A B L E _ I N T E R F A C E _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Reenables SAP operation over the interface
|
||
|
Arguments:
|
||
|
InterfaceIndex - unique index identifying interface to deactivate
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
EnableInterface(
|
||
|
IN ULONG InterfaceIndex
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
status = SapSetInterfaceEnable (InterfaceIndex, TRUE);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
case ERROR_CAN_NOT_COMPLETE:
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
D I S A B L E _ I N T E R F A C E _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Disables SAP operation over the interface
|
||
|
Arguments:
|
||
|
InterfaceIndex - unique index identifying interface to deactivate
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
DisableInterface(
|
||
|
IN ULONG InterfaceIndex
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
status = SapSetInterfaceEnable (InterfaceIndex, FALSE);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
case ERROR_CAN_NOT_COMPLETE:
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
D O _ U P D A T E _ S E R V I C E S _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Initiates update of services information over the interface
|
||
|
Completion of this update will be indicated by signalling
|
||
|
NotificationEvent passed at StartProtocol. GetEventMessage
|
||
|
can be used then to get the results of autostatic update
|
||
|
Arguments:
|
||
|
InterfaceIndex - unique index identifying interface to do
|
||
|
update on
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
UpdateServices(
|
||
|
IN ULONG InterfaceIndex
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
status = SapRequestUpdate (InterfaceIndex);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
case ERROR_CAN_NOT_COMPLETE:
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
M I B _ C R E A T E _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Entry point used by SNMP agent to create entries in SAP
|
||
|
tables. Currently the only table supported is Interface Table
|
||
|
(service table is accessed through router manager)
|
||
|
Arguments:
|
||
|
InputDataSize - must be size of sap interface info
|
||
|
InputData - SAP interface info
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
MibCreate(
|
||
|
IN ULONG InputDataSize,
|
||
|
IN PVOID InputData
|
||
|
) {
|
||
|
return ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
M I B _ D E L E T E _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Entry point used by SNMP agent to delete entries in SAP
|
||
|
tables. Currently the only table supported is Interface Table
|
||
|
(service table is accessed through router manager)
|
||
|
Arguments:
|
||
|
InputDataSize - must be size of sap interface info
|
||
|
InputData - SAP interface info
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
MibDelete(
|
||
|
IN ULONG InputDataSize,
|
||
|
IN PVOID InputData
|
||
|
) {
|
||
|
#define sapInputData ((PSAP_MIB_SET_INPUT_DATA)InputData)
|
||
|
DWORD status;
|
||
|
|
||
|
if (InputDataSize!=sizeof (SAP_MIB_SET_INPUT_DATA))
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
switch (sapInputData->TableId) {
|
||
|
case SAP_INTERFACE_TABLE:
|
||
|
status = SapDeleteSapInterface (
|
||
|
sapInputData->SapInterface.InterfaceIndex);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
break;
|
||
|
case ERROR_ALREADY_EXISTS:
|
||
|
status = ERROR_INVALID_PARAMETER;
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_INVALID_PARAMETER;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
#undef sapInputData
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
M I B _ S E T _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Entry point used by SNMP agent to set entries in SAP
|
||
|
tables. Currently the only table supported is Interface Table
|
||
|
(service table is accessed through router manager)
|
||
|
Arguments:
|
||
|
InputDataSize - must be size of sap interface info
|
||
|
InputData - SAP interface info
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
MibSet(
|
||
|
IN ULONG InputDataSize,
|
||
|
IN PVOID InputData
|
||
|
) {
|
||
|
#define sapInputData ((PSAP_MIB_SET_INPUT_DATA)InputData)
|
||
|
DWORD status;
|
||
|
|
||
|
if (InputDataSize!=sizeof (SAP_MIB_SET_INPUT_DATA))
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
switch (sapInputData->TableId) {
|
||
|
case SAP_INTERFACE_TABLE:
|
||
|
status = SapSetSapInterface (
|
||
|
sapInputData->SapInterface.InterfaceIndex,
|
||
|
&sapInputData->SapInterface.SapIfInfo);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
break;
|
||
|
case ERROR_ALREADY_EXISTS:
|
||
|
status = ERROR_INVALID_PARAMETER;
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_INVALID_PARAMETER;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
#undef sapInputData
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
M I B _ G E T _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Entry point used by SNMP agent to get entries from SAP
|
||
|
tables. Currently the only table supported is Interface Table
|
||
|
(service table is accessed through router manager)
|
||
|
Arguments:
|
||
|
InputDataSize - must be size of SAP_MIB_GET_INPUT_DATA
|
||
|
InputData - SAP mib get input data
|
||
|
OutputDataSize - on input: size of the output buffer
|
||
|
on output : size of output info or required
|
||
|
size of output buffer
|
||
|
if ERROR_INSUFFICIENT_BUFFER returned
|
||
|
OutputData - buffer to receive output data
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
ERROR_INSUFFICIENT_BUFFER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
MibGet(
|
||
|
IN ULONG InputDataSize,
|
||
|
IN PVOID InputData,
|
||
|
IN OUT PULONG OutputDataSize,
|
||
|
OUT PVOID OutputData
|
||
|
) {
|
||
|
#define sapInputData ((PSAP_MIB_GET_INPUT_DATA)InputData)
|
||
|
DWORD status;
|
||
|
|
||
|
if (InputDataSize!=sizeof (SAP_MIB_GET_INPUT_DATA))
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
switch (sapInputData->TableId) {
|
||
|
case SAP_BASE_ENTRY:
|
||
|
if (*OutputDataSize>=sizeof (SAP_MIB_BASE)) {
|
||
|
#define sapOutputData ((PSAP_MIB_BASE)OutputData)
|
||
|
|
||
|
sapOutputData->SapOperState = OperationalState;
|
||
|
status = NO_ERROR;
|
||
|
|
||
|
#undef sapOutputData
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_INSUFFICIENT_BUFFER;
|
||
|
*OutputDataSize = sizeof (SAP_MIB_BASE);
|
||
|
break;
|
||
|
|
||
|
case SAP_INTERFACE_TABLE:
|
||
|
if (*OutputDataSize>=sizeof (SAP_INTERFACE)) {
|
||
|
#define sapOutputData ((PSAP_INTERFACE)OutputData)
|
||
|
|
||
|
status = SapGetSapInterface (
|
||
|
sapInputData->InterfaceIndex,
|
||
|
&sapOutputData->SapIfInfo,
|
||
|
&sapOutputData->SapIfStats);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
sapOutputData->InterfaceIndex
|
||
|
= sapInputData->InterfaceIndex;
|
||
|
break;
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
break;
|
||
|
case ERROR_ALREADY_EXISTS:
|
||
|
status = ERROR_INVALID_PARAMETER;
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
|
||
|
#undef sapOutputData
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_INSUFFICIENT_BUFFER;
|
||
|
*OutputDataSize = sizeof (SAP_INTERFACE);
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_INVALID_PARAMETER;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
#undef sapInputData
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
M I B _ G E T _ F I R S T _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Entry point used by SNMP agent to get first entries from SAP
|
||
|
tables. Currently the only table supported is Interface Table
|
||
|
(service table is accessed through router manager)
|
||
|
Arguments:
|
||
|
InputDataSize - must be size of SAP_MIB_GET_INPUT_DATA
|
||
|
InputData - SAP mib get input data
|
||
|
OutputDataSize - on input: size of the output buffer
|
||
|
on output : size of output info or required
|
||
|
size of output buffer
|
||
|
if ERROR_INSUFFICIENT_BUFFER returned
|
||
|
OutputData - buffer to receive output data
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
ERROR_INSUFFICIENT_BUFFER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
MibGetFirst(
|
||
|
IN ULONG InputDataSize,
|
||
|
IN PVOID InputData,
|
||
|
IN OUT PULONG OutputDataSize,
|
||
|
OUT PVOID OutputData
|
||
|
) {
|
||
|
#define sapInputData ((PSAP_MIB_GET_INPUT_DATA)InputData)
|
||
|
DWORD status;
|
||
|
|
||
|
if (InputDataSize!=sizeof (SAP_MIB_GET_INPUT_DATA))
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
switch (sapInputData->TableId) {
|
||
|
case SAP_INTERFACE_TABLE:
|
||
|
if (*OutputDataSize>=sizeof (SAP_INTERFACE)) {
|
||
|
#define sapOutputData ((PSAP_INTERFACE)OutputData)
|
||
|
|
||
|
status = SapGetFirstSapInterface (
|
||
|
&sapOutputData->InterfaceIndex,
|
||
|
&sapOutputData->SapIfInfo,
|
||
|
&sapOutputData->SapIfStats);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
case ERROR_NO_MORE_ITEMS:
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#undef sapOutputData
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_INSUFFICIENT_BUFFER;
|
||
|
*OutputDataSize = sizeof (SAP_INTERFACE);
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_INVALID_PARAMETER;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
#undef sapInputData
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
M I B _ G E T _ N E X T _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Entry point used by SNMP agent to get next entries from SAP
|
||
|
tables. Currently the only table supported is Interface Table
|
||
|
(service table is accessed through router manager)
|
||
|
Arguments:
|
||
|
InputDataSize - must be size of SAP_MIB_GET_INPUT_DATA
|
||
|
InputData - SAP mib get input data
|
||
|
OutputDataSize - on input: size of the output buffer
|
||
|
on output : size of output info or required
|
||
|
size of output buffer
|
||
|
if ERROR_INSUFFICIENT_BUFFER returned
|
||
|
OutputData - buffer to receive output data
|
||
|
Return Value:
|
||
|
NO_ERROR
|
||
|
ERROR_CAN_NOT_COMPLETE
|
||
|
ERROR_INVALID_PARAMETER
|
||
|
ERROR_INSUFFICIENT_BUFFER
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
MibGetNext(
|
||
|
IN ULONG InputDataSize,
|
||
|
IN PVOID InputData,
|
||
|
IN OUT PULONG OutputDataSize,
|
||
|
OUT PVOID OutputData
|
||
|
) {
|
||
|
#define sapInputData ((PSAP_MIB_GET_INPUT_DATA)InputData)
|
||
|
DWORD status;
|
||
|
|
||
|
if (InputDataSize!=sizeof (SAP_MIB_GET_INPUT_DATA))
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
switch (sapInputData->TableId) {
|
||
|
case SAP_INTERFACE_TABLE:
|
||
|
if (*OutputDataSize>=sizeof (SAP_INTERFACE)) {
|
||
|
#define sapOutputData ((PSAP_INTERFACE)OutputData)
|
||
|
sapOutputData->InterfaceIndex
|
||
|
= sapInputData->InterfaceIndex;
|
||
|
status = SapGetNextSapInterface (
|
||
|
&sapOutputData->InterfaceIndex,
|
||
|
&sapOutputData->SapIfInfo,
|
||
|
&sapOutputData->SapIfStats);
|
||
|
switch (status) {
|
||
|
case NO_ERROR:
|
||
|
case ERROR_INVALID_PARAMETER:
|
||
|
case ERROR_NO_MORE_ITEMS:
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#undef sapOutputData
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_INSUFFICIENT_BUFFER;
|
||
|
*OutputDataSize = sizeof (SAP_INTERFACE);
|
||
|
break;
|
||
|
default:
|
||
|
status = ERROR_INVALID_PARAMETER;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
#undef sapInputData
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD WINAPI
|
||
|
MibSetTrapInfo(
|
||
|
IN HANDLE Event,
|
||
|
IN ULONG InputDataSize,
|
||
|
IN PVOID InputData,
|
||
|
OUT PULONG OutputDataSize,
|
||
|
OUT PVOID OutputData
|
||
|
) {
|
||
|
return ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
|
||
|
DWORD WINAPI
|
||
|
MibGetTrapInfo(
|
||
|
IN ULONG InputDataSize,
|
||
|
IN PVOID InputData,
|
||
|
OUT PULONG OutputDataSize,
|
||
|
OUT PVOID OutputData
|
||
|
) {
|
||
|
return ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
C R E A T E _ S T A T I C _ S E R V I C E _ E N T R Y _ P O I N T
|
||
|
|
||
|
Routine Description:
|
||
|
Adds service of IPX_PROTOCOL_STATIC to the table
|
||
|
Arguments:
|
||
|
InterfaceIndex - interface on which this server can be reached
|
||
|
ServiceEntry - server info
|
||
|
Return Value:
|
||
|
NO_ERROR - server was added ok
|
||
|
ERROR_CAN_NOT_COMPLETE - SAP agent is down
|
||
|
other - windows error code
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
CreateStaticService(
|
||
|
IN ULONG InterfaceIndex,
|
||
|
IN PIPX_STATIC_SERVICE_INFO ServiceEntry
|
||
|
) {
|
||
|
DWORD status;
|
||
|
IPX_SERVER_ENTRY_P Server;
|
||
|
IpxServerCpy (&Server, ServiceEntry);
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
SAP_IF_STATS ifStats;
|
||
|
status = SapGetSapInterface (InterfaceIndex, NULL, &ifStats);
|
||
|
if (status==NO_ERROR) {
|
||
|
status = UpdateServer (&Server,
|
||
|
InterfaceIndex,
|
||
|
IPX_PROTOCOL_STATIC,
|
||
|
INFINITE,
|
||
|
IPX_BCAST_NODE,
|
||
|
(ifStats.SapIfOperState!=OPER_STATE_DOWN)
|
||
|
? 0
|
||
|
: SDB_DISABLED_NODE_FLAG,
|
||
|
NULL);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
D E L E T E _ S T A T I C _ S E R V I C E _ E N T R Y _ P O I N T
|
||
|
|
||
|
Routine Description:
|
||
|
Deletes service of IPX_PROTOCOL_STATIC from the table
|
||
|
Arguments:
|
||
|
InterfaceIndex - interface on which this server can be reached
|
||
|
ServiceEntry - server info
|
||
|
Return Value:
|
||
|
NO_ERROR - service was deleted ok
|
||
|
ERROR_CAN_NOT_COMPLETE - SAP agent is down
|
||
|
other - windows error code
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
DeleteStaticService(
|
||
|
IN ULONG InterfaceIndex,
|
||
|
IN PIPX_STATIC_SERVICE_INFO ServiceEntry
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
IPX_SERVER_ENTRY_P Server;
|
||
|
IpxServerCpy (&Server, ServiceEntry); // Make local copy
|
||
|
Server.HopCount = IPX_MAX_HOP_COUNT; // because we need to change
|
||
|
// one of the fields
|
||
|
status = UpdateServer (&Server, InterfaceIndex,
|
||
|
IPX_PROTOCOL_STATIC, INFINITE, IPX_BCAST_NODE, 0, NULL);
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
B L O C K _ D E L E T E _ S T A T I C _ S E R V I C E S _ E N T R Y _ P O I N T
|
||
|
|
||
|
Routine Description:
|
||
|
Delete all services of IPX_PROTOCOL_STATIC
|
||
|
associated with given interface from the table
|
||
|
Arguments:
|
||
|
InterfaceIndex - interface index of interest
|
||
|
Return Value:
|
||
|
NO_ERROR - service was deleted ok
|
||
|
ERROR_CAN_NOT_COMPLETE - SAP agent is down
|
||
|
other - windows error code
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
BlockDeleteStaticServices(
|
||
|
IN ULONG InterfaceIndex
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
HANDLE enumHdl = NULL;
|
||
|
|
||
|
enumHdl = CreateListEnumerator (
|
||
|
SDB_INTF_LIST_LINK,
|
||
|
0xFFFF,
|
||
|
NULL,
|
||
|
InterfaceIndex,
|
||
|
IPX_PROTOCOL_STATIC,
|
||
|
SDB_DISABLED_NODE_FLAG);
|
||
|
if (enumHdl!=NULL) {
|
||
|
EnumerateServers (enumHdl, DeleteAllServersCB, enumHdl);
|
||
|
status = GetLastError ();
|
||
|
DeleteListEnumerator (enumHdl);
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
B L O C K _ C O N V E R T _ S E R V I C E S _ T O _ S T A T I C _ ENTRY_POINT
|
||
|
|
||
|
Routine Description:
|
||
|
Converts protocol iof all services associated with given interface to
|
||
|
IPX_PROTOCOL_STATIC
|
||
|
Arguments:
|
||
|
InterfaceIndex - interface index of interest
|
||
|
Return Value:
|
||
|
NO_ERROR - service was deleted ok
|
||
|
ERROR_CAN_NOT_COMPLETE - SAP agent is down
|
||
|
other - windows error code
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
BlockConvertServicesToStatic(
|
||
|
IN ULONG InterfaceIndex
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
HANDLE enumHdl = NULL;
|
||
|
|
||
|
enumHdl = CreateListEnumerator (
|
||
|
SDB_INTF_LIST_LINK,
|
||
|
0xFFFF,
|
||
|
NULL,
|
||
|
InterfaceIndex,
|
||
|
0xFFFFFFFF,
|
||
|
0);
|
||
|
if (enumHdl!=NULL) {
|
||
|
EnumerateServers (enumHdl, ConvertToStaticCB, enumHdl);
|
||
|
status = GetLastError ();
|
||
|
DeleteListEnumerator (enumHdl);
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
I S _ S E R V I C E _ E N T R Y _ P O I N T
|
||
|
|
||
|
Routine Description:
|
||
|
Check if service with given type and type is in the service table
|
||
|
and opianally return parameters of best entry for this service
|
||
|
Arguments:
|
||
|
Type - IPX Service type
|
||
|
Name - IPX Service name
|
||
|
Service - buffer that will be filled with the server info
|
||
|
Return Value:
|
||
|
TRUE - server was found
|
||
|
FALSE - server was not found or operation failed (call GetLastError()
|
||
|
to find out the reason for failure if any)
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
BOOL WINAPI
|
||
|
IsService(
|
||
|
IN USHORT Type,
|
||
|
IN PUCHAR Name,
|
||
|
OUT PIPX_SERVICE Service OPTIONAL
|
||
|
) {
|
||
|
DWORD status;
|
||
|
BOOL res;
|
||
|
IPX_SERVER_ENTRY_P Server;
|
||
|
ULONG InterfaceIndex;
|
||
|
ULONG Protocol;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
res = QueryServer (Type, Name,
|
||
|
&Server, &InterfaceIndex, &Protocol, NULL);
|
||
|
if (res) {
|
||
|
if (ARGUMENT_PRESENT (Service)) {
|
||
|
Service->InterfaceIndex = InterfaceIndex;
|
||
|
Service->Protocol = Protocol;
|
||
|
IpxServerCpy (&Service->Server, &Server);
|
||
|
}
|
||
|
status = NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
status = GetLastError ();
|
||
|
}
|
||
|
else {
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
res = FALSE;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
SetLastError (status);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
C R E A T E _ S E R V I C E _ E N U M E R A T I O N_ H A N D L E_ENTRY_POINT
|
||
|
|
||
|
Routine Description:
|
||
|
Create handle to start enumeration of the services in the STM table.
|
||
|
Arguments:
|
||
|
ExclusionFlags - Flags to limit enumeration to certain
|
||
|
types of servers
|
||
|
CriteriaService - Criteria for exclusion flags
|
||
|
Return Value:
|
||
|
Enumeration handle
|
||
|
NULL - if operation failed (call GetLastError () to get reason
|
||
|
failure)
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
HANDLE WINAPI
|
||
|
CreateServiceEnumerationHandle(
|
||
|
IN DWORD ExclusionFlags,
|
||
|
IN PIPX_SERVICE CriteriaService
|
||
|
) {
|
||
|
HANDLE handle;
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
INT idx;
|
||
|
if (ExclusionFlags & STM_ONLY_THIS_NAME)
|
||
|
idx = SDB_HASH_TABLE_LINK;
|
||
|
else if (ExclusionFlags & STM_ONLY_THIS_TYPE)
|
||
|
idx = SDB_TYPE_LIST_LINK;
|
||
|
else if (ExclusionFlags & STM_ONLY_THIS_INTERFACE)
|
||
|
idx = SDB_INTF_LIST_LINK;
|
||
|
else
|
||
|
idx = SDB_HASH_TABLE_LINK;
|
||
|
|
||
|
handle = CreateListEnumerator (idx,
|
||
|
(USHORT)((ExclusionFlags & STM_ONLY_THIS_TYPE)
|
||
|
? CriteriaService->Server.Type : 0xFFFF),
|
||
|
((ExclusionFlags & STM_ONLY_THIS_NAME)
|
||
|
? CriteriaService->Server.Name : NULL),
|
||
|
((ExclusionFlags & STM_ONLY_THIS_INTERFACE)
|
||
|
? CriteriaService->InterfaceIndex
|
||
|
: INVALID_INTERFACE_INDEX),
|
||
|
((ExclusionFlags & STM_ONLY_THIS_PROTOCOL)
|
||
|
? CriteriaService->Protocol : 0xFFFFFFFFL),
|
||
|
SDB_DISABLED_NODE_FLAG);
|
||
|
if (handle!=NULL)
|
||
|
status = NO_ERROR;
|
||
|
else
|
||
|
status = GetLastError ();
|
||
|
}
|
||
|
else {
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
handle = NULL;
|
||
|
}
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
SetLastError (status);
|
||
|
return handle;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
E N U M E R A T E _ G E T _ N E X T _ S E R V I C E _ E N T R Y _ P O I N T
|
||
|
|
||
|
Routine Description:
|
||
|
Get next service in the enumeration started by
|
||
|
CreateServiceEnumerationHandle
|
||
|
Arguments:
|
||
|
EnumerationHandle - Handle that identifies this
|
||
|
enumeration
|
||
|
Service - buffer to place parameters of next service entry
|
||
|
to be returned by enumeration
|
||
|
Return Value:
|
||
|
NO_ERROR - next service was placed in provided buffer or
|
||
|
ERROR_NO_MORE_ITEMS - there are no more services to be
|
||
|
returned in the enumeration
|
||
|
ERROR_CAN_NOT_COMPLETE - operation failed.
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
EnumerateGetNextService(
|
||
|
IN HANDLE EnumerationHandle,
|
||
|
OUT PIPX_SERVICE Service
|
||
|
) {
|
||
|
DWORD status;
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
if (EnumerateServers (EnumerationHandle, GetOneCB, Service))
|
||
|
status = NO_ERROR;
|
||
|
else {
|
||
|
if (GetLastError()==NO_ERROR)
|
||
|
status = ERROR_NO_MORE_ITEMS;
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
C L O S E _ S E R V I C E _ E N U M E R A T I O N _ H A N D L E _ENTRY_POINT
|
||
|
|
||
|
Routine Description:
|
||
|
Frees resources associated with enumeration.
|
||
|
Arguments:
|
||
|
EnumerationHandle - Handle that identifies this
|
||
|
enumeration
|
||
|
Return Value:
|
||
|
NO_ERROR - operation succeded
|
||
|
ERROR_CAN_NOT_COMPLETE - operation failed.
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
CloseServiceEnumerationHandle(
|
||
|
IN HANDLE EnumerationHandle
|
||
|
) {
|
||
|
DWORD status;
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
DeleteListEnumerator (EnumerationHandle);
|
||
|
status = NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
return status;
|
||
|
}
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
G E T _ F I R S T _ O R D E R E D _ S E R V I C E _ E N T R Y _ P O I N T
|
||
|
|
||
|
Routine Description:
|
||
|
Find and return first service in the order specified by the ordering method.
|
||
|
Search is limited only to certain types of services as specified by the
|
||
|
exclusion flags end corresponding fields in Server parameter.
|
||
|
Returns ERROR_NO_MORE_ITEMS if there are no services in the
|
||
|
table that meet specified criteria.
|
||
|
Arguments:
|
||
|
OrderingMethod - which ordering to consider in determining what is
|
||
|
the first server
|
||
|
ExclusionFlags - flags to limit search to certain servers according
|
||
|
to specified criteria
|
||
|
Server - On input: criteria for exclusion flags
|
||
|
On output: first service entry in the specified order
|
||
|
Return Value:
|
||
|
NO_ERROR - server was found that meets specified criteria
|
||
|
ERROR_NO_MORE_ITEMS - no server exist with specified criteria
|
||
|
other - operation failed (windows error code)
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
GetFirstOrderedService(
|
||
|
IN DWORD OrderingMethod,
|
||
|
IN DWORD ExclusionFlags,
|
||
|
IN OUT PIPX_SERVICE Service
|
||
|
) {
|
||
|
DWORD status;
|
||
|
IPX_SERVER_ENTRY_P Server;
|
||
|
IpxServerCpy (&Server, &Service->Server);
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
status = GetFirstServer (OrderingMethod, ExclusionFlags,
|
||
|
&Server, &Service->InterfaceIndex, &Service->Protocol);
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
if (status==NO_ERROR)
|
||
|
IpxServerCpy (&Service->Server, &Server);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
G E T _ N E X T _ O R D E R E D _ S E R V I C E _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Find and return next service in the order specified by the ordering method.
|
||
|
Search starts from specified service and is limited only to certain types
|
||
|
of services as specified by the exclusion flags and corresponding fields
|
||
|
in Server parameter.
|
||
|
Arguments:
|
||
|
OrderingMethod - which ordering to consider in determining what is
|
||
|
the first server
|
||
|
ExclusionFlags - flags to limit search to certain servers according
|
||
|
to fields of Server
|
||
|
Server - On input server entry from which to compute the next
|
||
|
On output: first service entry in the specified order
|
||
|
Return Value:
|
||
|
NO_ERROR - server was found that meets specified criteria
|
||
|
ERROR_NO_MORE_ITEMS - no server exist with specified criteria
|
||
|
other - operation failed (windows error code)
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
GetNextOrderedService(
|
||
|
IN DWORD OrderingMethod,
|
||
|
IN DWORD ExclusionFlags,
|
||
|
IN OUT PIPX_SERVICE Service
|
||
|
) {
|
||
|
DWORD status;
|
||
|
IPX_SERVER_ENTRY_P Server;
|
||
|
IpxServerCpy (&Server, &Service->Server);
|
||
|
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
status = GetNextServer (OrderingMethod, ExclusionFlags,
|
||
|
&Server, &Service->InterfaceIndex, &Service->Protocol);
|
||
|
}
|
||
|
else
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
if (status==NO_ERROR)
|
||
|
IpxServerCpy (&Service->Server, &Server);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
G E T _ S E R V I C E _ C O U N T _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Returns total number of services is the table
|
||
|
Arguments:
|
||
|
None
|
||
|
Return Value:
|
||
|
Number of services in the table
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
ULONG WINAPI WINAPI
|
||
|
GetServiceCount(
|
||
|
void
|
||
|
) {
|
||
|
DWORD status;
|
||
|
ULONG count;
|
||
|
EnterCriticalSection (&OperationalStateLock);
|
||
|
|
||
|
if (OperationalState==OPER_STATE_UP) {
|
||
|
count = ServerTable.ST_ServerCnt;
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
else {
|
||
|
count = 0;
|
||
|
status = ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
LeaveCriticalSection (&OperationalStateLock);
|
||
|
SetLastError (status);
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
GetRouteMetric (
|
||
|
IN UCHAR Network[4],
|
||
|
OUT PUSHORT Metric
|
||
|
) {
|
||
|
IPX_MIB_GET_INPUT_DATA MibGetInputData;
|
||
|
IPX_ROUTE Route;
|
||
|
DWORD RtSize;
|
||
|
DWORD rc;
|
||
|
|
||
|
RtSize = sizeof(IPX_ROUTE);
|
||
|
MibGetInputData.TableId = IPX_DEST_TABLE;
|
||
|
IpxNetCpy (MibGetInputData.MibIndex.RoutingTableIndex.Network, Network);
|
||
|
|
||
|
rc = (*MIBEntryGet) (IPX_PROTOCOL_BASE,
|
||
|
sizeof(IPX_MIB_GET_INPUT_DATA),
|
||
|
&MibGetInputData,
|
||
|
&RtSize,
|
||
|
&Route);
|
||
|
if (rc==NO_ERROR)
|
||
|
*Metric = Route.TickCount;
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
*******************************************************************
|
||
|
R E G I S T E R _ P R O T O C O L _ E N T R Y _ P O I N T
|
||
|
Routine Description:
|
||
|
Register protocol dll with router manager
|
||
|
Identifies protocol handled by the dll and supported functionality
|
||
|
Arguments:
|
||
|
Protocol - buffer to return protocol ID
|
||
|
SupportedFunctionality - buffer to set flags indicating functionality
|
||
|
supported by the dll
|
||
|
Return Value:
|
||
|
NO_ERROR - SAP agent was started OK
|
||
|
ERROR_CAN_NOT_COMPLETE - operation can not be completed
|
||
|
|
||
|
*******************************************************************
|
||
|
--*/
|
||
|
DWORD WINAPI
|
||
|
RegisterProtocol(
|
||
|
IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
|
||
|
IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar
|
||
|
)
|
||
|
{
|
||
|
if(pRoutingChar->dwProtocolId != IPX_PROTOCOL_SAP)
|
||
|
{
|
||
|
return ERROR_NOT_SUPPORTED;
|
||
|
}
|
||
|
|
||
|
pRoutingChar->fSupportedFunctionality = 0;
|
||
|
pServiceChar->fSupportedFunctionality = SERVICES|DEMAND_UPDATE_SERVICES;
|
||
|
|
||
|
pRoutingChar->pfnStartProtocol = StartProtocol;
|
||
|
pRoutingChar->pfnStopProtocol = StopProtocol;
|
||
|
pRoutingChar->pfnAddInterface = AddInterface;
|
||
|
pRoutingChar->pfnDeleteInterface = DeleteInterface;
|
||
|
pRoutingChar->pfnGetEventMessage = GetEventMessage;
|
||
|
pRoutingChar->pfnGetInterfaceInfo = GetInterfaceConfigInfo;
|
||
|
pRoutingChar->pfnSetInterfaceInfo = SetInterfaceConfigInfo;
|
||
|
pRoutingChar->pfnBindInterface = BindInterface;
|
||
|
pRoutingChar->pfnUnbindInterface = UnbindInterface;
|
||
|
pRoutingChar->pfnEnableInterface = EnableInterface;
|
||
|
pRoutingChar->pfnDisableInterface = DisableInterface;
|
||
|
pRoutingChar->pfnGetGlobalInfo = GetGlobalInfo;
|
||
|
pRoutingChar->pfnSetGlobalInfo = SetGlobalInfo;
|
||
|
pRoutingChar->pfnMibCreateEntry = MibCreate;
|
||
|
pRoutingChar->pfnMibDeleteEntry = MibDelete;
|
||
|
pRoutingChar->pfnMibGetEntry = MibGet;
|
||
|
pRoutingChar->pfnMibSetEntry = MibSet;
|
||
|
pRoutingChar->pfnMibGetFirstEntry = MibGetFirst;
|
||
|
pRoutingChar->pfnMibGetNextEntry = MibGetNext;
|
||
|
pRoutingChar->pfnUpdateRoutes = NULL;
|
||
|
|
||
|
pServiceChar->pfnIsService = IsService;
|
||
|
pServiceChar->pfnUpdateServices = UpdateServices;
|
||
|
pServiceChar->pfnCreateServiceEnumerationHandle = CreateServiceEnumerationHandle;
|
||
|
pServiceChar->pfnEnumerateGetNextService = EnumerateGetNextService;
|
||
|
pServiceChar->pfnCloseServiceEnumerationHandle = CloseServiceEnumerationHandle;
|
||
|
pServiceChar->pfnGetServiceCount = GetServiceCount;
|
||
|
pServiceChar->pfnCreateStaticService = CreateStaticService;
|
||
|
pServiceChar->pfnDeleteStaticService = DeleteStaticService;
|
||
|
pServiceChar->pfnBlockConvertServicesToStatic = BlockConvertServicesToStatic;
|
||
|
pServiceChar->pfnBlockDeleteStaticServices = BlockDeleteStaticServices;
|
||
|
pServiceChar->pfnGetFirstOrderedService = GetFirstOrderedService;
|
||
|
pServiceChar->pfnGetNextOrderedService = GetNextOrderedService;
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|