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.
1003 lines
31 KiB
1003 lines
31 KiB
#include "precomp.h"
|
|
DEBUG_FILEZONE(ZONE_T120_T123PSTN);
|
|
|
|
/* SCF.cpp
|
|
*
|
|
* Copyright (c) 1994-1995 by DataBeam Corporation, Lexington, KY
|
|
*
|
|
* Abstract:
|
|
* This is the implementation file for the CLayerSCF class
|
|
*
|
|
* Private Instance Variables:
|
|
* Remote_Call_Reference - List of active SCFCalls initiated by the
|
|
* remote site
|
|
* Call_Reference - List of active SCFCalls initiated locally
|
|
* DLCI_List - This list matches DLCIs to SCFCalls, its
|
|
* only real purpose is for DisconnectRequest()
|
|
* Message_List - List of OwnerCallback messages that can't
|
|
* be processed immediately.
|
|
* m_pT123 - Address of owner object
|
|
* m_pQ922 - Address of lower layer
|
|
* m_nMsgBase - Message base passed in by owner. Used in
|
|
* OwnerCallback
|
|
* Identifier - Identifier passed to lower layer
|
|
* Link_Originator - TRUE if we initiated the connection
|
|
* Maximum_Packet_Size - Maximum packet size transmittable
|
|
* DataLink_Struct - Address of structure holding DataLink parms
|
|
* Data_Request_Memory_Manager - Address of memory manager
|
|
* Lower_Layer_Prepend - Holds number of bytes prepended to packet
|
|
* by the lower layer
|
|
* Lower_Layer_Append - Holds number of bytes appended to packet by
|
|
* the lower layer
|
|
* Call_Reference_Base - This value holds the next call reference
|
|
* number.
|
|
*
|
|
* Caveats:
|
|
* None.
|
|
*
|
|
* Authors:
|
|
* James W. Lawwill
|
|
*/
|
|
#include "scf.h"
|
|
|
|
|
|
/*
|
|
* CLayerSCF::CLayerSCF (
|
|
* PTransportResources transport_resources,
|
|
* IObject * owner_object,
|
|
* IProtocolLayer * lower_layer,
|
|
* USHORT message_base,
|
|
* USHORT identifier,
|
|
* BOOL link_originator,
|
|
* PChar config_file)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This is the CLayerSCF constructor. This routine initializes all
|
|
* variables and allocates buffer space.
|
|
*/
|
|
CLayerSCF::CLayerSCF
|
|
(
|
|
T123 *owner_object,
|
|
CLayerQ922 *pQ922, // lower layer
|
|
USHORT message_base,
|
|
USHORT identifier,
|
|
BOOL link_originator,
|
|
PDataLinkParameters datalink_struct,
|
|
PMemoryManager data_request_memory_manager,
|
|
BOOL * initialized
|
|
)
|
|
:
|
|
Remote_Call_Reference (TRANSPORT_HASHING_BUCKETS),
|
|
Call_Reference (TRANSPORT_HASHING_BUCKETS),
|
|
DLCI_List (TRANSPORT_HASHING_BUCKETS),
|
|
m_pT123(owner_object),
|
|
m_nMsgBase(message_base),
|
|
m_pQ922(pQ922)
|
|
{
|
|
ProtocolLayerError error;
|
|
|
|
TRACE_OUT(("CLayerSCF::CLayerSCF"));
|
|
|
|
Link_Originator = (USHORT)link_originator;
|
|
Identifier = identifier;
|
|
Data_Request_Memory_Manager = data_request_memory_manager;
|
|
Call_Reference_Base = 1;
|
|
*initialized = TRUE;
|
|
|
|
|
|
/*
|
|
** Fill in the DataLink_Struct with the proposed values and the default
|
|
** values
|
|
*/
|
|
DataLink_Struct.k_factor = datalink_struct -> k_factor;
|
|
DataLink_Struct.default_k_factor = datalink_struct -> default_k_factor;
|
|
DataLink_Struct.n201 = datalink_struct -> n201;
|
|
DataLink_Struct.default_n201 = datalink_struct -> default_n201;
|
|
DataLink_Struct.t200 = datalink_struct -> t200;
|
|
DataLink_Struct.default_t200 = datalink_struct -> default_t200;
|
|
|
|
/*
|
|
** Find the maximum packet size
|
|
*/
|
|
m_pQ922->GetParameters(
|
|
&Maximum_Packet_Size,
|
|
&Lower_Layer_Prepend,
|
|
&Lower_Layer_Append);
|
|
|
|
/*
|
|
** Register with the lower layer
|
|
*/
|
|
error = m_pQ922->RegisterHigherLayer(
|
|
Identifier,
|
|
Data_Request_Memory_Manager,
|
|
(IProtocolLayer *) this);
|
|
|
|
if (error != PROTOCOL_LAYER_NO_ERROR)
|
|
{
|
|
ERROR_OUT(("Multiplexer: constructor: Error registering with lower layer"));
|
|
*initialized = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* CLayerSCF::~CLayerSCF (void)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This is the CLayerSCF destructor. This routine cleans up everything.
|
|
*/
|
|
CLayerSCF::~CLayerSCF (void)
|
|
{
|
|
TRACE_OUT(("CLayerSCF::~CLayerSCF"));
|
|
|
|
PMessageStruct message;
|
|
PSCFCall lpSCFCall;
|
|
|
|
m_pQ922->RemoveHigherLayer(Identifier);
|
|
|
|
/*
|
|
** Delete all locally initiated calls
|
|
*/
|
|
Call_Reference.reset();
|
|
while (Call_Reference.iterate ((PDWORD_PTR) &lpSCFCall))
|
|
{
|
|
delete lpSCFCall;
|
|
}
|
|
|
|
/*
|
|
** Delete all remotely initiated calls
|
|
*/
|
|
Remote_Call_Reference.reset();
|
|
while (Remote_Call_Reference.iterate ((PDWORD_PTR) &lpSCFCall))
|
|
{
|
|
delete lpSCFCall;
|
|
}
|
|
|
|
/*
|
|
** Delete all passive owner callbacks
|
|
*/
|
|
Message_List.reset();
|
|
while (Message_List.iterate ((PDWORD_PTR) &message))
|
|
{
|
|
delete message;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* CLayerSCF::ConnectRequest (
|
|
* DLCI dlci,
|
|
* TransportPriority priority)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function initiates a connection with the remote site. As a result,
|
|
* we will create a SCFCall and tell it to initiate a connection.
|
|
*/
|
|
SCFError CLayerSCF::ConnectRequest (
|
|
DLCI dlci,
|
|
TransportPriority priority)
|
|
|
|
{
|
|
TRACE_OUT(("CLayerSCF::ConnectRequest"));
|
|
|
|
BOOL initialized;
|
|
CallReference call_reference;
|
|
SCFError return_value = SCF_NO_ERROR;
|
|
PSCFCall lpSCFCall;
|
|
|
|
|
|
/*
|
|
** Get the next valid local call reference value.
|
|
*/
|
|
call_reference = GetNextCallReference ();
|
|
|
|
if (call_reference == 0)
|
|
return (SCF_CONNECTION_FULL);
|
|
|
|
/*
|
|
** Create an SCFCall object to handle this call reference
|
|
*/
|
|
DBG_SAVE_FILE_LINE
|
|
lpSCFCall= new SCFCall(this,
|
|
m_pQ922,
|
|
call_reference << 8,
|
|
&DataLink_Struct,
|
|
Data_Request_Memory_Manager,
|
|
&initialized);
|
|
|
|
if (lpSCFCall != NULL)
|
|
{
|
|
if (initialized)
|
|
{
|
|
Call_Reference.insert ((DWORD_PTR) call_reference, (DWORD_PTR) lpSCFCall);
|
|
/*
|
|
** Register the DLCI and the call reference
|
|
*/
|
|
DLCI_List.insert ((DWORD_PTR) dlci, (DWORD_PTR) lpSCFCall);
|
|
|
|
lpSCFCall->ConnectRequest (call_reference, dlci, priority);
|
|
}
|
|
else
|
|
{
|
|
delete lpSCFCall;
|
|
return_value = SCF_MEMORY_ALLOCATION_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return_value = SCF_MEMORY_ALLOCATION_ERROR;
|
|
}
|
|
|
|
return (return_value);
|
|
}
|
|
|
|
|
|
/*
|
|
* CLayerSCF::ConnectResponse (
|
|
* CallReference call_reference,
|
|
* DLCI dlci,
|
|
* BOOL valid_dlci)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This is the CLayerSCF destructor. This routine cleans up everything.
|
|
*/
|
|
SCFError CLayerSCF::ConnectResponse (
|
|
CallReference call_reference,
|
|
DLCI dlci,
|
|
BOOL valid_dlci)
|
|
|
|
{
|
|
TRACE_OUT(("CLayerSCF::ConnectResponse"));
|
|
|
|
PSCFCall lpSCFCall = NULL;
|
|
|
|
if (valid_dlci)
|
|
{
|
|
if (Remote_Call_Reference.find ((DWORD_PTR) call_reference, (PDWORD_PTR) &lpSCFCall))
|
|
DLCI_List.insert ((DWORD_PTR) dlci, (DWORD_PTR) lpSCFCall);
|
|
}
|
|
|
|
if(NULL != lpSCFCall)
|
|
{
|
|
lpSCFCall->ConnectResponse (valid_dlci);
|
|
return (SCF_NO_ERROR);
|
|
}
|
|
return (SCF_NO_SUCH_DLCI);
|
|
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* SCFError CLayerSCF::DisconnectRequest (
|
|
* DLCI dlci)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function calls the SCFCall associated with the DLCI and starts
|
|
* the disconnect operation
|
|
*/
|
|
SCFError CLayerSCF::DisconnectRequest (
|
|
DLCI dlci)
|
|
|
|
{
|
|
TRACE_OUT(("CLayerSCF::DisconnectRequest"));
|
|
|
|
PSCFCall lpSCFCall;
|
|
|
|
if (DLCI_List.find ((DWORD_PTR) dlci, (PDWORD_PTR) &lpSCFCall) == FALSE)
|
|
return (SCF_NO_SUCH_DLCI);
|
|
|
|
lpSCFCall->DisconnectRequest ();
|
|
|
|
return (SCF_NO_ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
* SCFError CLayerSCF::DataIndication (
|
|
* LPBYTE packet_address,
|
|
* ULONG buffer_size,
|
|
* PULong packet_length)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called by the lower layer when it has received a
|
|
* packet for us to process.
|
|
*/
|
|
ProtocolLayerError CLayerSCF::DataIndication (
|
|
LPBYTE packet_address,
|
|
ULONG packet_length,
|
|
PULong bytes_accepted)
|
|
{
|
|
TRACE_OUT(("CLayerSCF::DataIndication"));
|
|
|
|
BOOL legal_packet;
|
|
CallReference call_reference;
|
|
USHORT length_call_reference;
|
|
USHORT message_type;
|
|
PSCFCall call;
|
|
USHORT remainder_length;
|
|
USHORT local;
|
|
BOOL initialized;
|
|
|
|
|
|
remainder_length = (USHORT) packet_length;
|
|
*bytes_accepted = packet_length;
|
|
|
|
if (*(packet_address+PROTOCOL_DISCRIMINATOR) != Q931_PROTOCOL_DISCRIMINATOR)
|
|
return (PROTOCOL_LAYER_NO_ERROR);
|
|
|
|
/*
|
|
** Get the call reference value
|
|
*/
|
|
call_reference = *(packet_address + CALL_REFERENCE_VALUE);
|
|
if (call_reference == 0)
|
|
{
|
|
ERROR_OUT(("CLayerSCF: DataIndication: illegal call reference value = 0"));
|
|
return (PROTOCOL_LAYER_NO_ERROR);
|
|
}
|
|
|
|
length_call_reference = *(packet_address + LENGTH_CALL_REFERENCE);
|
|
packet_address += CALL_REFERENCE_VALUE + length_call_reference;
|
|
remainder_length -= (CALL_REFERENCE_VALUE + length_call_reference);
|
|
|
|
|
|
/*
|
|
** Get the message type
|
|
*/
|
|
message_type = *(packet_address++);
|
|
remainder_length--;
|
|
|
|
switch (message_type)
|
|
{
|
|
case SETUP:
|
|
/*
|
|
** If the call reference is already active, return error
|
|
*/
|
|
if (Remote_Call_Reference.find ((DWORD) call_reference))
|
|
{
|
|
TRACE_OUT(("CLayerSCF: DataIndication: SETUP: call reference is already active"));
|
|
break;
|
|
}
|
|
|
|
if ((call_reference & CALL_REFERENCE_ORIGINATOR) == 1)
|
|
{
|
|
TRACE_OUT(("CLayerSCF: DataIndication: SETUP: call reference Originator bit is set incorrectly"));
|
|
break;
|
|
}
|
|
|
|
/*
|
|
** This is a new call reference, create a new SCFCall to handle
|
|
** the call. Since the remote site initiated the call, put this
|
|
** reference in the Remote array
|
|
*/
|
|
call= new SCFCall(this,
|
|
m_pQ922,
|
|
(call_reference << 8),
|
|
&DataLink_Struct,
|
|
Data_Request_Memory_Manager,
|
|
&initialized);
|
|
|
|
if (call != NULL)
|
|
{
|
|
if (initialized)
|
|
{
|
|
|
|
Remote_Call_Reference.insert ((DWORD_PTR) call_reference, (DWORD_PTR) call);
|
|
/*
|
|
** Allow the call to process the SETUP command
|
|
*/
|
|
legal_packet = call->ProcessSetup (call_reference, packet_address, remainder_length);
|
|
|
|
/*
|
|
** If the packet was illegal, remove the reference
|
|
*/
|
|
if (legal_packet == FALSE) {
|
|
delete call;
|
|
Remote_Call_Reference.remove ((DWORD) call_reference);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete call;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case CONNECT:
|
|
/*
|
|
** The call originator bit must be set to signify that we are
|
|
** the originators of the call
|
|
*/
|
|
if ((call_reference & CALL_REFERENCE_ORIGINATOR) == 0)
|
|
{
|
|
TRACE_OUT(("CLayerSCF: DataIndication: CONNECT: call reference Originator bit is set incorrectly"));
|
|
break;
|
|
}
|
|
|
|
/*
|
|
** If the call reference is not already active, return error
|
|
*/
|
|
call_reference &= CALL_ORIGINATOR_MASK;
|
|
if (Call_Reference.find ((DWORD_PTR) call_reference, (PDWORD_PTR) &call) == FALSE)
|
|
{
|
|
TRACE_OUT(("CLayerSCF: DataIndication: CONNECT: call reference is not already active = %x", call_reference));
|
|
break;
|
|
}
|
|
|
|
call->ProcessConnect (packet_address, remainder_length);
|
|
break;
|
|
|
|
case CONNECT_ACKNOWLEDGE:
|
|
/*
|
|
** If the call reference is already active, return error
|
|
*/
|
|
if (Remote_Call_Reference.find ((DWORD_PTR) call_reference, (PDWORD_PTR) &call) == FALSE)
|
|
{
|
|
TRACE_OUT(("CLayerSCF: DataIndication: CONNECT_ACK: call reference is not active"));
|
|
break;
|
|
}
|
|
|
|
/*
|
|
** The call originator bit should NOT be set
|
|
*/
|
|
if ((call_reference & CALL_REFERENCE_ORIGINATOR) == 1)
|
|
{
|
|
TRACE_OUT(("CLayerSCF: DataIndication: CONNECT_ACK: call reference Originator bit is set incorrectly"));
|
|
break;
|
|
}
|
|
|
|
call->ProcessConnectAcknowledge (packet_address, remainder_length);
|
|
break;
|
|
|
|
case RELEASE_COMPLETE:
|
|
local = call_reference & CALL_REFERENCE_ORIGINATOR;
|
|
call_reference &= CALL_ORIGINATOR_MASK;
|
|
|
|
/*
|
|
** If the call is local, check the Call_Reference list for validity
|
|
*/
|
|
if (local)
|
|
{
|
|
if (Call_Reference.find ((DWORD_PTR) call_reference, (PDWORD_PTR) &call) == FALSE)
|
|
{
|
|
TRACE_OUT(("CLayerSCF: DataIndication: RELEASE_COMPLETE: call reference is not already active"));
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** If the call is remote, check the Call_Reference list for
|
|
** validity
|
|
*/
|
|
if (Remote_Call_Reference.find ((DWORD_PTR) call_reference, (PDWORD_PTR) &call) == FALSE)
|
|
{
|
|
TRACE_OUT(("CLayerSCF: DataIndication: RELEASE_COMPLETE: call reference is not already active"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
call -> ProcessReleaseComplete (packet_address, remainder_length);
|
|
ProcessMessages ();
|
|
break;
|
|
|
|
case DISCONNECT:
|
|
case RELEASE:
|
|
case STATUS:
|
|
case STATUS_ENQUIRY:
|
|
TRACE_OUT(("CLayerSCF:DataIndication: Illegal command received = %x", message_type));
|
|
|
|
local = call_reference & CALL_REFERENCE_ORIGINATOR;
|
|
call_reference &= CALL_ORIGINATOR_MASK;
|
|
|
|
/*
|
|
** If the call is local, check the Call_Reference list for validity
|
|
*/
|
|
if (local)
|
|
{
|
|
if (Call_Reference.find ((DWORD_PTR) call_reference, (PDWORD_PTR) &call) == FALSE)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** If the call is remote, check the Call_Reference list for
|
|
** validity
|
|
*/
|
|
if (Remote_Call_Reference.find ((DWORD_PTR) call_reference, (PDWORD_PTR) &call) == FALSE)
|
|
break;
|
|
}
|
|
|
|
call -> DisconnectRequest ();
|
|
break;
|
|
|
|
default:
|
|
ERROR_OUT(("CLayerSCF:DataIndication: Unrecognized command received = %x", message_type));
|
|
break;
|
|
}
|
|
return (PROTOCOL_LAYER_NO_ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
* ProtocolLayerError CLayerSCF::PollTransmitter (
|
|
* ULONG,
|
|
* USHORT data_to_transmit,
|
|
* USHORT * pending_data,
|
|
* USHORT *)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function should be called frequently to allow the SCF calls to
|
|
* transmit packets.
|
|
*/
|
|
ProtocolLayerError CLayerSCF::PollTransmitter (
|
|
ULONG_PTR,
|
|
USHORT data_to_transmit,
|
|
USHORT * pending_data,
|
|
USHORT *)
|
|
{
|
|
// TRACE_OUT(("CLayerSCF::PollTransmitter"));
|
|
|
|
USHORT local_pending_data;
|
|
PSCFCall lpSCFCall;
|
|
|
|
*pending_data = 0;
|
|
|
|
/*
|
|
** Go through each of the locally originated calls and attempt to transmit
|
|
** data.
|
|
*/
|
|
Call_Reference.reset();
|
|
while (Call_Reference.iterate ((PDWORD_PTR) &lpSCFCall))
|
|
{
|
|
lpSCFCall->PollTransmitter (data_to_transmit, &local_pending_data);
|
|
*pending_data |= local_pending_data;
|
|
}
|
|
|
|
|
|
/*
|
|
** Go through each of the remotely originated calls and attempt to transmit
|
|
** data.
|
|
*/
|
|
Remote_Call_Reference.reset();
|
|
while (Remote_Call_Reference.iterate ((PDWORD_PTR) &lpSCFCall))
|
|
{
|
|
lpSCFCall-> PollTransmitter (data_to_transmit, &local_pending_data);
|
|
*pending_data |= local_pending_data;
|
|
}
|
|
|
|
ProcessMessages ();
|
|
|
|
return (PROTOCOL_LAYER_NO_ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
* SCFError CLayerSCF::DataRequest (
|
|
* ULONG,
|
|
* LPBYTE,
|
|
* ULONG,
|
|
* PULong)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function can not be called. This layer does not permit data
|
|
* requests from higher layers.
|
|
*/
|
|
ProtocolLayerError CLayerSCF::DataRequest (
|
|
ULONG_PTR,
|
|
LPBYTE,
|
|
ULONG,
|
|
PULong)
|
|
{
|
|
return (PROTOCOL_LAYER_ERROR);
|
|
}
|
|
|
|
/*
|
|
* SCFError CLayerSCF::DataRequest (
|
|
* ULONG,
|
|
* PMemory,
|
|
* USHORT *)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function can not be called. This layer does not permit data
|
|
* requests from higher layers.
|
|
*/
|
|
ProtocolLayerError CLayerSCF::DataRequest (
|
|
ULONG_PTR,
|
|
PMemory,
|
|
PULong)
|
|
{
|
|
return (PROTOCOL_LAYER_ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
* void CLayerSCF::PollReceiver (
|
|
* ULONG)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description
|
|
* This function only checks its passive callback list. If this function
|
|
* had a higher layer that it was passing data too, it would do that. But
|
|
* since it has no higher layer, it doesn't do much.
|
|
*/
|
|
ProtocolLayerError CLayerSCF::PollReceiver(void)
|
|
{
|
|
ProcessMessages ();
|
|
|
|
return (PROTOCOL_LAYER_NO_ERROR);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* CallReference CLayerSCF::GetNextCallReference ()
|
|
*
|
|
* Functional Description
|
|
* This function searches the local call reference list for a valid call
|
|
* reference number. If it can not find one, it returns 0. Valid call
|
|
* references are 1-127.
|
|
*
|
|
* Formal Parameters
|
|
* None
|
|
*
|
|
* Return Value
|
|
* Call reference value
|
|
*
|
|
* Side Effects
|
|
* None
|
|
*
|
|
* Caveats
|
|
* None
|
|
*/
|
|
USHORT CLayerSCF::GetNextCallReference ()
|
|
{
|
|
USHORT call_reference;
|
|
|
|
if (Call_Reference.entries() == 127)
|
|
return (0);
|
|
|
|
call_reference = Call_Reference_Base;
|
|
Call_Reference_Base++;
|
|
if (Call_Reference_Base == 128)
|
|
Call_Reference_Base = 1;
|
|
|
|
while (Call_Reference.find ((DWORD) call_reference))
|
|
{
|
|
call_reference++;
|
|
if (call_reference == 128)
|
|
call_reference = 1;
|
|
}
|
|
|
|
return (call_reference);
|
|
}
|
|
|
|
|
|
/*
|
|
* ULONG CLayerSCF::OwnerCallback (
|
|
* USHORT message,
|
|
* ULONG parameter1,
|
|
* ULONG parameter2,
|
|
* PVoid parameter3)
|
|
*
|
|
* Functional Description
|
|
* This function is called by the SCFCall objects when they need to
|
|
* communicate a message to us. If the message can not be processed
|
|
* immediately, it is saved in a message structure and processed at a
|
|
* later time.
|
|
*
|
|
* Formal Parameters
|
|
* None
|
|
*
|
|
* Return Value
|
|
* Message dependent
|
|
*
|
|
* Side Effects
|
|
* None
|
|
*
|
|
* Caveats
|
|
* None
|
|
*/
|
|
ULONG CLayerSCF::OwnerCallback
|
|
(
|
|
ULONG message,
|
|
void *parameter1,
|
|
void *parameter2,
|
|
void *parameter3
|
|
)
|
|
{
|
|
TRACE_OUT(("CLayerSCF::OwnerCallback"));
|
|
|
|
ULONG actual_message;
|
|
CallReference call_reference;
|
|
PMessageStruct passive_message;
|
|
PNetworkConnectStruct connect_struct;
|
|
PSCFCall lpSCFCall;
|
|
|
|
/*
|
|
** The upper byte of the message is the call reference message that it
|
|
** represents
|
|
*/
|
|
call_reference = (CallReference) (message >> 8);
|
|
actual_message = message & 0xff;
|
|
|
|
switch (actual_message)
|
|
{
|
|
case NETWORK_CONNECT_CONFIRM:
|
|
|
|
/*
|
|
** A CONNECT_CONFIRM message is returned by the SCFCall when a call
|
|
** that we originated, has been established. We register the
|
|
** SCFCall with the DLCI and call the owner object.
|
|
*/
|
|
connect_struct = (PNetworkConnectStruct) parameter3;
|
|
connect_struct -> call_reference = call_reference;
|
|
|
|
if (Call_Reference.find ((DWORD_PTR) call_reference, (PDWORD_PTR) &lpSCFCall))
|
|
{
|
|
DLCI_List.insert ((DWORD_PTR) connect_struct->dlci, (DWORD_PTR) lpSCFCall);
|
|
}
|
|
|
|
m_pT123->OwnerCallback(m_nMsgBase + actual_message, 0, 0, parameter3);
|
|
break;
|
|
|
|
case NETWORK_CONNECT_INDICATION:
|
|
/*
|
|
** A CONNECT_INDICATION message is returned by the SCFCall when the
|
|
** remote SCF wants to create a new call. We will call the owner
|
|
** of this object to see if he will accept the DLCI requested.
|
|
*/
|
|
connect_struct = (PNetworkConnectStruct) parameter3;
|
|
connect_struct -> call_reference = call_reference;
|
|
|
|
m_pT123->OwnerCallback(m_nMsgBase + actual_message, 0, 0, parameter3);
|
|
break;
|
|
|
|
case NETWORK_DISCONNECT_INDICATION:
|
|
/*
|
|
** This message is received from the SCFCall when one side wants
|
|
** to terminate the call. We treat this message differently than
|
|
** the other messages because it involves the deletion of an
|
|
** SCFCall object. Don't forget, if we delete the object and then
|
|
** return to it at the end of this procedure, a GPF could occur.
|
|
*/
|
|
DBG_SAVE_FILE_LINE
|
|
passive_message = new MessageStruct;
|
|
if (NULL != passive_message)
|
|
{
|
|
passive_message -> message = message;
|
|
passive_message -> parameter1 = parameter1;
|
|
passive_message -> parameter2 = parameter2;
|
|
passive_message -> parameter3 = parameter3;
|
|
Message_List.append ((DWORD_PTR) passive_message);
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(("CLayerSCF::OwnerCallback: cannot allocate MessageStruct"));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ERROR_OUT(("CLayerSCF: Illegal message: %x", actual_message));
|
|
break;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* ProtocolLayerError CLayerSCF::GetParameters (
|
|
* USHORT,
|
|
* USHORT *,
|
|
* USHORT *,
|
|
* USHORT *)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description
|
|
* This function is not valid in this layer. It must exist because this
|
|
* class inherits from inherits from ProtocolLayer and it is a pure virtual
|
|
* function.
|
|
*/
|
|
ProtocolLayerError CLayerSCF::GetParameters (
|
|
USHORT *,
|
|
USHORT *,
|
|
USHORT *)
|
|
{
|
|
return (PROTOCOL_LAYER_REGISTRATION_ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
* ProtocolLayerError CLayerSCF::RegisterHigherLayer (
|
|
* USHORT,
|
|
* PMemoryManager,
|
|
* IProtocolLayer *)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description
|
|
* This function is not valid in this layer. It must exist because this
|
|
* class inherits from inherits from ProtocolLayer and it is a pure virtual
|
|
* function.
|
|
*/
|
|
ProtocolLayerError CLayerSCF::RegisterHigherLayer (
|
|
ULONG_PTR,
|
|
PMemoryManager,
|
|
IProtocolLayer *)
|
|
{
|
|
return (PROTOCOL_LAYER_REGISTRATION_ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
* ProtocolLayerError CLayerSCF::RemoveHigherLayer (
|
|
* USHORT)
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description
|
|
* This function is not valid in this layer. It must exist because this
|
|
* class inherits from inherits from ProtocolLayer and it is a pure virtual
|
|
* function.
|
|
*/
|
|
ProtocolLayerError CLayerSCF::RemoveHigherLayer (
|
|
ULONG_PTR)
|
|
{
|
|
return (PROTOCOL_LAYER_REGISTRATION_ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
* void CLayerSCF::ProcessMessages ()
|
|
*
|
|
* Functional Description
|
|
* This function is called periodically to check its passive messages.
|
|
* Passive messages occur when the SCF gets a callback but can't process
|
|
* it immediately. Therefore, it puts the message and its parameters in
|
|
* a structure and saves the message for later.
|
|
*
|
|
* Formal Parameters
|
|
* None
|
|
*
|
|
* Return Value
|
|
* Message dependent
|
|
*
|
|
* Side Effects
|
|
* None
|
|
*
|
|
* Caveats
|
|
* None
|
|
*/
|
|
void CLayerSCF::ProcessMessages ()
|
|
{
|
|
// TRACE_OUT(("CLayerSCF::ProcessMessages"));
|
|
|
|
PMessageStruct message;
|
|
CallReference call_reference;
|
|
ULONG actual_message;
|
|
USHORT call_originator;
|
|
USHORT cause;
|
|
DLCI dlci;
|
|
BOOL call_reference_valid;
|
|
void *parameter1;
|
|
void *parameter2;
|
|
PSCFCall lpSCFCall;
|
|
|
|
/*
|
|
** Go thru each message in the list
|
|
*/
|
|
while (Message_List.isEmpty() == FALSE)
|
|
{
|
|
/*
|
|
** Remote the first message from the list
|
|
*/
|
|
message = (PMessageStruct) Message_List.get ();
|
|
|
|
call_reference = (CallReference) ((message -> message) >> 8);
|
|
actual_message = (message -> message) & 0xff;
|
|
parameter1 = message -> parameter1;
|
|
parameter2 = message -> parameter2;
|
|
|
|
switch (actual_message)
|
|
{
|
|
case NETWORK_DISCONNECT_INDICATION:
|
|
/*
|
|
** This message is received from the SCFCall when one side
|
|
** wants to terminate the call. We treat this message
|
|
** differently than the other messages because it involves the
|
|
** deletion of an SCFCall object.
|
|
*/
|
|
dlci = (DLCI) parameter1;
|
|
call_originator = (USHORT) (((ULONG_PTR) parameter2) >> 16);
|
|
cause = (USHORT) ((ULONG_PTR) parameter2) & 0xffff;
|
|
|
|
/*
|
|
** dlci is 0 if the SCFCall was never assigned a DLCI by the
|
|
** remote site.
|
|
*/
|
|
if (dlci != 0)
|
|
DLCI_List.remove ((DWORD) dlci);
|
|
|
|
/*
|
|
** If the SCFCall was the call originator, its reference is
|
|
** in Call_Reference, otherwise it is in Remote_Call_Reference.
|
|
**
|
|
** Check the Call_Reference list to make sure that the
|
|
** call_reference is valid. The way passive owner callbacks
|
|
** work, it is possible to receive a DISCONNECT for a callback
|
|
** that was already disconnected.
|
|
*/
|
|
call_reference_valid = FALSE;
|
|
if (call_originator)
|
|
{
|
|
if (Call_Reference.find ((DWORD_PTR) call_reference, (PDWORD_PTR) &lpSCFCall))
|
|
{
|
|
delete lpSCFCall;
|
|
Call_Reference.remove ((DWORD) call_reference);
|
|
call_reference_valid = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Remote_Call_Reference.find ((DWORD_PTR) call_reference, (PDWORD_PTR) &lpSCFCall))
|
|
{
|
|
delete lpSCFCall;
|
|
Remote_Call_Reference.remove ((DWORD_PTR) call_reference);
|
|
call_reference_valid = TRUE;
|
|
}
|
|
}
|
|
|
|
if (call_reference_valid)
|
|
{
|
|
/*
|
|
** If the cause of the disconnect was because the Requested
|
|
** channel was unavailable, we will tell the owner of this
|
|
** layer to retry the connection.
|
|
*/
|
|
if (cause == REQUESTED_CHANNEL_UNAVAILABLE)
|
|
{
|
|
parameter2 = (void *) ((((ULONG_PTR) call_originator) << 16) | TRUE);
|
|
}
|
|
else
|
|
{
|
|
parameter2 = (void *) ((((ULONG_PTR) call_originator) << 16) | FALSE);
|
|
}
|
|
|
|
/*
|
|
** Let the owner of this object know that a disconnect has
|
|
** occured.
|
|
*/
|
|
m_pT123->OwnerCallback(m_nMsgBase + NETWORK_DISCONNECT_INDICATION,
|
|
parameter1, parameter2);
|
|
}
|
|
break;
|
|
}
|
|
|
|
/*
|
|
** Delete the message structure
|
|
*/
|
|
delete message;
|
|
}
|
|
}
|
|
|