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.
533 lines
16 KiB
533 lines
16 KiB
/***********************************************************************
|
|
* *
|
|
* Filename: fsmapi.c *
|
|
* Module: H245 Finite State Machine Subsystem *
|
|
* *
|
|
***********************************************************************
|
|
* INTEL Corporation Proprietary Information *
|
|
* *
|
|
* This listing is supplied under the terms of a license agreement *
|
|
* with INTEL Corporation and may not be copied nor disclosed except *
|
|
* in accordance with the terms of that agreement. *
|
|
* *
|
|
* Copyright (c) 1996 Intel Corporation. All rights reserved. *
|
|
***********************************************************************
|
|
* *
|
|
* $Workfile: FSMAPI.C $
|
|
* $Revision: 1.12 $
|
|
* $Modtime: 09 Dec 1996 13:34:24 $
|
|
* $Log L:\mphone\h245\h245env\comm\h245_3\h245_fsm\vcs\src\fsmapi.c_v $
|
|
* *
|
|
***********************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "h245api.h"
|
|
#include "h245com.h"
|
|
#include "h245fsm.h"
|
|
#include "h245deb.x"
|
|
|
|
|
|
|
|
extern char *EntityName[];
|
|
|
|
|
|
|
|
/*
|
|
* This table maps FSM stateless events into H.245 API events
|
|
*/
|
|
static WORD StatelessTable[NUM_EVENTS - NUM_STATE_EVENTS] =
|
|
{
|
|
H245_IND_NONSTANDARD_REQUEST, // NonStandardRequestPDU
|
|
H245_IND_NONSTANDARD_RESPONSE, // NonStandardResponsePDU
|
|
H245_IND_NONSTANDARD_COMMAND, // NonStandardCommandPDU
|
|
H245_IND_NONSTANDARD, // NonStandardIndicationPDU
|
|
H245_IND_MISC_COMMAND, // MiscellaneousCommandPDU
|
|
H245_IND_MISC, // MiscellaneousIndicationPDU
|
|
H245_IND_COMM_MODE_REQUEST, // CommunicationModeRequestPDU
|
|
H245_IND_COMM_MODE_RESPONSE, // CommunicationModeResponsePDU
|
|
H245_IND_COMM_MODE_COMMAND, // CommunicationModeCommandPDU
|
|
H245_IND_CONFERENCE_REQUEST, // ConferenceRequestPDU
|
|
H245_IND_CONFERENCE_RESPONSE, // ConferenceResponsePDU
|
|
H245_IND_CONFERENCE_COMMAND, // ConferenceCommandPDU
|
|
H245_IND_CONFERENCE, // ConferenceIndicationPDU
|
|
H245_IND_SEND_TERMCAP, // SendTerminalCapabilitySetPDU
|
|
H245_IND_ENCRYPTION, // EncryptionCommandPDU
|
|
H245_IND_FLOW_CONTROL, // FlowControlCommandPDU
|
|
H245_IND_ENDSESSION, // EndSessionCommandPDU
|
|
H245_IND_FUNCTION_NOT_UNDERSTOOD, // FunctionNotUnderstoodIndicationPDU
|
|
H245_IND_JITTER, // JitterIndicationPDU
|
|
H245_IND_H223_SKEW, // H223SkewIndicationPDU
|
|
H245_IND_NEW_ATM_VC, // NewATMVCIndicationPDU
|
|
H245_IND_USERINPUT, // UserInputIndicationPDU
|
|
H245_IND_H2250_MAX_SKEW, // H2250MaximumSkewIndicationPDU
|
|
H245_IND_MC_LOCATION, // MCLocationIndicationPDU
|
|
H245_IND_VENDOR_ID, // VendorIdentificationIndicationPDU
|
|
H245_IND_FUNCTION_NOT_SUPPORTED, // FunctionNotSupportedIndicationPDU
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
* Configurable counter values
|
|
*/
|
|
|
|
unsigned int uN100 = 10; // Master Slave Determination
|
|
|
|
|
|
|
|
/*
|
|
* Configurable timer values
|
|
*/
|
|
|
|
unsigned int uT101 = 30000; // Capability Exchange
|
|
unsigned int uT102 = 30000; // Maintenance Loop
|
|
unsigned int uT103 = 30000; // Logical Channel Signalling
|
|
unsigned int uT104 = 30000; // H.223 Multiplex Table
|
|
unsigned int uT105 = 30000; // Round Trip Delay
|
|
unsigned int uT106 = 30000; // Master Slave Determination
|
|
unsigned int uT107 = 30000; // Request Multiplex Entry
|
|
unsigned int uT108 = 30000; // Send Logical Channel
|
|
unsigned int uT109 = 30000; // Mode Request
|
|
|
|
|
|
|
|
/*
|
|
* NAME
|
|
* ObjectCreate - create an State Entity object
|
|
*
|
|
*
|
|
* PARAMETERS
|
|
* INPUT pInst Pointer to FSM instance data
|
|
* INPUT Entity State Entity represented by object, e.g. LCSE_OUT
|
|
* INPUT Key Lookup key for distinguish multiple instances of SE
|
|
* INPUT dwTransId Transaction identifier to be sent up to client
|
|
*
|
|
* RETURN VALUE
|
|
* pObject Function succeeded
|
|
* NULL Memory allocation failed
|
|
*/
|
|
|
|
Object_t *
|
|
ObjectCreate(struct InstanceStruct *pInstance, Entity_t Entity, Key_t Key, DWORD_PTR dwTransId)
|
|
{
|
|
register Object_t * pObject;
|
|
|
|
#if defined(_DEBUG)
|
|
H245TRACE(pInstance->dwInst, 4, "ObjectCreate: Entity=%s(%d) Key=%d dwTransID=0x%p",
|
|
EntityName[Entity], Entity, Key, dwTransId);
|
|
#else
|
|
H245TRACE(pInstance->dwInst, 4, "ObjectCreate: Entity=%d Key=%d dwTransID=0x%p",
|
|
Entity, Key, dwTransId);
|
|
#endif
|
|
|
|
pObject = (Object_t *)MemAlloc(sizeof(*pObject));
|
|
if (pObject == NULL)
|
|
{
|
|
H245TRACE(pInstance->dwInst, 1, "ObjectCreate: FSM Object memory allocation failed");
|
|
return NULL;
|
|
}
|
|
memset(pObject, 0, sizeof(*pObject));
|
|
|
|
/* copy primitive variables to my object */
|
|
pObject->pInstance = pInstance;
|
|
pObject->dwInst = pInstance->dwInst;
|
|
pObject->dwTransId = dwTransId;
|
|
pObject->Key = Key;
|
|
pObject->Entity = Entity;
|
|
|
|
pObject->pNext = pInstance->StateMachine.Object_tbl[Entity];
|
|
pInstance->StateMachine.Object_tbl[Entity] = pObject;
|
|
|
|
return pObject;
|
|
} // ObjectCreate()
|
|
|
|
|
|
|
|
/*
|
|
* NAME
|
|
* ObjectDestroy - deallocate an object created by ObjectCreate()
|
|
*
|
|
*
|
|
* PARAMETERS
|
|
* INPUT pInst pointer to FSM instance data
|
|
* INPUT id index into the object table
|
|
*
|
|
* RETURN VALUE
|
|
* FALSE object deallocated
|
|
* TRUE object not found
|
|
*/
|
|
|
|
int
|
|
ObjectDestroy(Object_t *pObject)
|
|
{
|
|
struct InstanceStruct * pInstance;
|
|
Object_t * pSearch;
|
|
Object_t * pPrev;
|
|
|
|
ASSERT(pObject != NULL);
|
|
ASSERT(pObject->uNestLevel == 0);
|
|
ASSERT(pObject->pInstance != NULL);
|
|
pInstance = pObject->pInstance;
|
|
|
|
#if defined(_DEBUG)
|
|
H245TRACE(pInstance->dwInst, 4, "ObjectDestroy: Entity=%s(%d) Key=%d State=%d",
|
|
EntityName[pObject->Entity], pObject->Entity, pObject->Key, pObject->State);
|
|
#else
|
|
H245TRACE(pInstance->dwInst, 4, "ObjectDestroy: Entity=%d Key=%d State=%d",
|
|
pObject->Entity, pObject->Key, pObject->State);
|
|
#endif
|
|
|
|
if (pObject->dwTimerId)
|
|
{
|
|
H245TRACE(pObject->dwInst, 4, "ObjectDestroy: stoping timer");
|
|
FsmStopTimer(pObject);
|
|
}
|
|
|
|
if (pInstance->StateMachine.Object_tbl[pObject->Entity] == NULL)
|
|
{
|
|
H245TRACE(pInstance->dwInst, 1, "ObjectDestroy: no State Entity of specified type found");
|
|
return TRUE;
|
|
}
|
|
|
|
if (pInstance->StateMachine.Object_tbl[pObject->Entity] == pObject)
|
|
{
|
|
pInstance->StateMachine.Object_tbl[pObject->Entity] = pObject->pNext;
|
|
MemFree(pObject);
|
|
return FALSE;
|
|
}
|
|
|
|
pPrev = pInstance->StateMachine.Object_tbl[pObject->Entity];
|
|
pSearch = pPrev->pNext;
|
|
while (pSearch != NULL)
|
|
{
|
|
if (pSearch == pObject)
|
|
{
|
|
pPrev->pNext = pSearch->pNext;
|
|
MemFree(pObject);
|
|
return FALSE;
|
|
}
|
|
pPrev = pSearch;
|
|
pSearch = pSearch->pNext;
|
|
}
|
|
|
|
H245TRACE(pInstance->dwInst, 1, "ObjectDestroy: State Entity not found");
|
|
return TRUE;
|
|
} // ObjectDestroy()
|
|
|
|
|
|
|
|
/*
|
|
* NAME
|
|
* ObjectFind - given parsed information of a PDU, it searches the object table for
|
|
* an object with a matching id, type and category
|
|
*
|
|
*
|
|
* PARAMETERS
|
|
* INPUT pInst
|
|
* INPUT Category category of a given PDU
|
|
* INPUT Type type of the PDU
|
|
* INPUT pdu_id unique id shared by PDU and object (usually channel number or sequence number)
|
|
*
|
|
* RETURN VALUE
|
|
* pObject object found
|
|
* NULL object not found
|
|
*/
|
|
|
|
Object_t *
|
|
ObjectFind(struct InstanceStruct *pInstance, Entity_t Entity, Key_t Key)
|
|
{
|
|
register Object_t * pObject;
|
|
|
|
ASSERT(Entity < STATELESS);
|
|
pObject = pInstance->StateMachine.Object_tbl[Entity];
|
|
while (pObject != NULL)
|
|
{
|
|
if (pObject->Key == Key)
|
|
{
|
|
#if defined(_DEBUG)
|
|
H245TRACE(pInstance->dwInst, 4, "ObjectFind(%s, %d) object found",
|
|
EntityName[Entity], Key);
|
|
#else
|
|
H245TRACE(pInstance->dwInst, 4, "ObjectFind(%d, %d) object found",
|
|
Entity, Key);
|
|
#endif
|
|
return pObject;
|
|
}
|
|
pObject = pObject->pNext;
|
|
}
|
|
|
|
#if defined(_DEBUG)
|
|
H245TRACE(pInstance->dwInst, 4, "ObjectFind(%s, %d) object not found",
|
|
EntityName[Entity], Key);
|
|
#else
|
|
H245TRACE(pInstance->dwInst, 4, "ObjectFind(%d, %d) object not found",
|
|
Entity, Key);
|
|
#endif
|
|
return NULL;
|
|
} // ObjectFind()
|
|
|
|
|
|
|
|
/*
|
|
* NAME
|
|
* SendFunctionNotUnderstood - builds and sends Function Not Supported PDU
|
|
*
|
|
*
|
|
* PARAMETERS
|
|
* INPUT dwInst Current H.245 instance
|
|
* INPUT pPdu Not supported PDU
|
|
*
|
|
* RETURN VALUE
|
|
* H245_ERROR_OK
|
|
*/
|
|
|
|
|
|
HRESULT
|
|
SendFunctionNotUnderstood(struct InstanceStruct *pInstance, PDU_t *pPdu)
|
|
{
|
|
PDU_t * pOut;
|
|
HRESULT lError;
|
|
|
|
pOut = MemAlloc(sizeof(*pOut));
|
|
if (pOut == NULL)
|
|
{
|
|
return H245_ERROR_NOMEM;
|
|
}
|
|
|
|
switch (pPdu->choice)
|
|
{
|
|
case MltmdSystmCntrlMssg_rqst_chosen:
|
|
pOut->u.indication.u.functionNotUnderstood.choice = FnctnNtUndrstd_request_chosen;
|
|
pOut->u.indication.u.functionNotUnderstood.u.FnctnNtUndrstd_request =
|
|
pPdu->u.MltmdSystmCntrlMssg_rqst;
|
|
break;
|
|
|
|
case MSCMg_rspns_chosen:
|
|
pOut->u.indication.u.functionNotUnderstood.choice = FnctnNtUndrstd_response_chosen;
|
|
pOut->u.indication.u.functionNotUnderstood.u.FnctnNtUndrstd_response =
|
|
pPdu->u.MSCMg_rspns;
|
|
break;
|
|
|
|
case MSCMg_cmmnd_chosen:
|
|
pOut->u.indication.u.functionNotUnderstood.choice = FnctnNtUndrstd_command_chosen;
|
|
pOut->u.indication.u.functionNotUnderstood.u.FnctnNtUndrstd_command =
|
|
pPdu->u.MSCMg_cmmnd;
|
|
break;
|
|
|
|
default:
|
|
// Can't reply to unsupported indication...
|
|
MemFree(pOut);
|
|
return H245_ERROR_OK;
|
|
} // switch (Type)
|
|
|
|
pOut->choice = indication_chosen;
|
|
pOut->u.indication.choice = functionNotUnderstood_chosen;
|
|
lError = sendPDU(pInstance, pOut);
|
|
MemFree(pOut);
|
|
return lError;
|
|
} // SendFunctionNotUnderstood()
|
|
|
|
|
|
|
|
/*
|
|
* NAME
|
|
* FsmOutgoing - process outbound PDU
|
|
*
|
|
*
|
|
* PARAMETERS
|
|
* INPUT pInst Pointer to FSM instance structure
|
|
* INPUT pPdu Pointer to PDU to send
|
|
* INPUT dwTransId Transaction identifier to use for response
|
|
*
|
|
* RETURN VALUE
|
|
* Error codes defined in h245com.h
|
|
*/
|
|
|
|
HRESULT
|
|
FsmOutgoing(struct InstanceStruct *pInstance, PDU_t *pPdu, DWORD_PTR dwTransId)
|
|
{
|
|
HRESULT lError;
|
|
Entity_t Entity;
|
|
Event_t Event;
|
|
Key_t Key;
|
|
int bCreate;
|
|
Object_t * pObject;
|
|
|
|
ASSERT(pInstance != NULL);
|
|
ASSERT(pPdu != NULL);
|
|
H245TRACE(pInstance->dwInst, 4, "FsmOutgoing");
|
|
|
|
#if defined(_DEBUG)
|
|
if (check_pdu(pInstance, pPdu))
|
|
return H245_ERROR_ASN1;
|
|
#endif // (DEBUG)
|
|
|
|
lError = PduParseOutgoing(pInstance, pPdu, &Entity, &Event, &Key, &bCreate);
|
|
if (lError != H245_ERROR_OK)
|
|
{
|
|
H245TRACE(pInstance->dwInst, 1,
|
|
"FsmOutgoing: PDU not recognized; Error=%d", lError);
|
|
return lError;
|
|
}
|
|
|
|
ASSERT(Entity < NUM_ENTITYS);
|
|
|
|
if (Entity == STATELESS)
|
|
{
|
|
H245TRACE(pInstance->dwInst, 4, "FsmOutgoing: Sending stateless PDU");
|
|
return sendPDU(pInstance, pPdu);
|
|
}
|
|
|
|
ASSERT(Event < NUM_STATE_EVENTS);
|
|
|
|
pObject = ObjectFind(pInstance, Entity, Key);
|
|
if (pObject == NULL)
|
|
{
|
|
if (bCreate == FALSE)
|
|
{
|
|
#if defined(_DEBUG)
|
|
H245TRACE(pInstance->dwInst, 1,
|
|
"FsmOutgoing: State Entity %s(%d) not found; Key=%d",
|
|
EntityName[Entity], Entity, Key);
|
|
#else
|
|
H245TRACE(pInstance->dwInst, 1,
|
|
"FsmOutgoing: State Entity %d not found; Key=%d",
|
|
Entity, Key);
|
|
#endif
|
|
return H245_ERROR_PARAM;
|
|
}
|
|
pObject = ObjectCreate(pInstance, Entity, Key, dwTransId);
|
|
if (pObject == NULL)
|
|
{
|
|
H245TRACE(pInstance->dwInst, 1, "FsmOutgoing: State Entity memory allocation failed");
|
|
return H245_ERROR_NOMEM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pObject->dwTransId = dwTransId;
|
|
}
|
|
|
|
return StateMachine(pObject, pPdu, Event);
|
|
} // FsmOutgoing()
|
|
|
|
|
|
|
|
/*
|
|
* NAME
|
|
* FsmIncoming - process inbound PDU
|
|
*
|
|
*
|
|
* PARAMETERS
|
|
* INPUT dwInst current H.245 instance
|
|
* INPUT pPdu pointer to a PDU structure
|
|
*
|
|
* RETURN VALUE
|
|
* error codes defined in h245com.h (not checked)
|
|
*/
|
|
|
|
HRESULT
|
|
FsmIncoming(struct InstanceStruct *pInstance, PDU_t *pPdu)
|
|
{
|
|
HRESULT lError;
|
|
Entity_t Entity;
|
|
Event_t Event;
|
|
Key_t Key;
|
|
int bCreate;
|
|
Object_t * pObject;
|
|
Object_t * pObject1;
|
|
|
|
ASSERT(pInstance != NULL);
|
|
ASSERT(pPdu != NULL);
|
|
H245TRACE(pInstance->dwInst, 4, "FsmIncoming");
|
|
|
|
lError = PduParseIncoming(pInstance, pPdu, &Entity, &Event, &Key, &bCreate);
|
|
if (lError != H245_ERROR_OK)
|
|
{
|
|
H245TRACE(pInstance->dwInst, 1,
|
|
"FsmIncoming: Received PDU not recognized", lError);
|
|
SendFunctionNotUnderstood(pInstance, pPdu);
|
|
return lError;
|
|
}
|
|
|
|
ASSERT(Entity < NUM_ENTITYS);
|
|
|
|
if (Entity == STATELESS)
|
|
{
|
|
H245TRACE(pInstance->dwInst, 4, "FsmIncoming: Received stateless PDU");
|
|
return H245FsmIndication(pPdu, (DWORD)StatelessTable[Event - NUM_STATE_EVENTS], pInstance, 0, H245_ERROR_OK);
|
|
}
|
|
|
|
ASSERT(Event < NUM_STATE_EVENTS);
|
|
|
|
if (Event == MaintenanceLoopOffCommandPDU)
|
|
{
|
|
// Special case MaintenanceLoopOff applies to ALL loops
|
|
ASSERT(Entity == MLSE_IN);
|
|
pObject = pInstance->StateMachine.Object_tbl[Entity];
|
|
if (pObject == NULL)
|
|
{
|
|
return H245_ERROR_OK;
|
|
}
|
|
lError = StateMachine(pObject, pPdu, Event);
|
|
pObject = pInstance->StateMachine.Object_tbl[Entity];
|
|
while (pObject)
|
|
{
|
|
if (pObject->uNestLevel == 0)
|
|
{
|
|
pObject1 = pObject;
|
|
pObject = pObject->pNext;
|
|
ObjectDestroy(pObject1);
|
|
}
|
|
else
|
|
{
|
|
pObject->State = 0;
|
|
pObject = pObject->pNext;
|
|
}
|
|
}
|
|
return lError;
|
|
} // if
|
|
|
|
pObject = ObjectFind(pInstance, Entity, Key);
|
|
if (pObject == NULL)
|
|
|
|
{
|
|
if (bCreate == FALSE)
|
|
{
|
|
#if defined(_DEBUG)
|
|
H245TRACE(pInstance->dwInst, 1,
|
|
"FsmIncoming: State Entity %s(%d) not found; Key=%d",
|
|
EntityName[Entity], Entity, Key);
|
|
#else
|
|
H245TRACE(pInstance->dwInst, 1,
|
|
"FsmIncoming: State Entity %d not found; Key=%d",
|
|
Entity, Key);
|
|
#endif
|
|
return H245_ERROR_PARAM;
|
|
}
|
|
pObject = ObjectCreate(pInstance, Entity, Key, 0);
|
|
if (pObject == NULL)
|
|
{
|
|
H245TRACE(pInstance->dwInst, 1, "FsmIncoming: State Entity memory allocation failed");
|
|
return H245_ERROR_NOMEM;
|
|
}
|
|
}
|
|
|
|
return StateMachine(pObject, pPdu, Event);
|
|
} // FsmIncoming()
|
|
|
|
|
|
// CAVEAT: Need to save dwInst since StateMachine() might deallocate pObject!
|
|
HRESULT
|
|
FsmTimerEvent(struct InstanceStruct *pInstance, DWORD_PTR dwTimerId, Object_t *pObject, Event_t Event)
|
|
{
|
|
ASSERT(pInstance != NULL);
|
|
ASSERT(pObject != NULL);
|
|
ASSERT(pObject->pInstance == pInstance);
|
|
ASSERT(pObject->dwTimerId == dwTimerId);
|
|
H245TRACE(pInstance->dwInst, 4, "FsmTimerEvent");
|
|
pObject->dwTimerId = 0;
|
|
return StateMachine(pObject, NULL, Event);
|
|
} // FsmTimerEvent()
|
|
|