windows-nt/Source/XPSP1/NT/enduser/netmeeting/t120/mst123/scfcall.cpp
2020-09-26 16:20:57 +08:00

1465 lines
42 KiB
C++

#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_T123PSTN);
/* SCFCall.cpp
*
* Copyright (c) 1994-1995 by DataBeam Corporation, Lexington, KY
*
* Abstract:
* This class is instantiated by the SCF class. For each call that the
* local site or remote site initiates, a SCFCall object is instantiated.
* SCF can can manage 254 different calls simultaneously. For each call
* there is a specific Q.933 based protocol that must occur to make the
* connection valid. This object sends and receives the Q.933 packets.
*
* Private Instance Variables:
* m_pSCF - Address of the owner of this object
* Lower_Layer - Address of the layer below this layer
* m_nMsgBase - The owner of this object gives it a base
* number to use for OwnerCallbacks ()
* Maximum_Packet_Size - Maximum transmittable packet size
* Packet_Pending - Tells which packet is to be transmitted
* next.
* Link_Originator - TRUE is this site initiated the call
*
* Write_Buffer - Address of write buffer
* Send_Priority - TRUE if we are suppose to respond to the
* priority requested by the remote site
*
* Call_Reference - Call reference number of this call.
* DLCI - Holds the suggested and confirmed DLCI for
* this call.
* Priority - Holds the suggested and confirmed priority
* for this call.
*
* State - Holds the current state of the call.
* Release_Cause - Reason the the breakup of the link.
* Default_Priority - Default priority of a non-specified call.
*
* T303_Timeout - T303 timeout value.
* T303_Handle - System timer handle to T303 timer
* T303_Active - TRUE if the timer is currently active
* T303_Count - Number of T303 Timeouts
*
* T313_Timeout - T313 timeout value
* T313_Handle - System timer handle to T313 timer
* T313_Active - TRUE if the timer is currently active.
*
* Caveats:
* None.
*
* Authors:
* James W. Lawwill
*/
#include "scf.h"
#include "scfcall.h"
/*
* SCFCall::SCFCall (
* PTransportResources transport_resources,
* IObject * owner_object
* IProtocolLayer * lower_layer,
* USHORT message_base,
* PDataLinkParameters datalink_struct,
* PMemoryManager data_request_memory_manager,
* BOOL * initialized)
*
* Public
*
* Functional Description:
* This is the SCFCall constructor. This routine initializes all
* variables and allocates write buffer space.
*/
SCFCall::SCFCall (
CLayerSCF *owner_object,
IProtocolLayer * lower_layer,
USHORT message_base,
PDataLinkParameters datalink_struct,
PMemoryManager data_request_memory_manager,
BOOL * initialized)
{
TRACE_OUT(("SCFCall::SCFCall"));
m_pSCF = owner_object;
Lower_Layer = lower_layer;
m_nMsgBase = message_base;
Data_Request_Memory_Manager = data_request_memory_manager;
*initialized = TRUE;
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;
/*
** T200 is represented in milliseconds, we need to convert it to
** tenths of seconds.
*/
DataLink_Struct.t200 = datalink_struct->t200 / 100;
DataLink_Struct.default_t200 = datalink_struct->default_t200 / 100;
Lower_Layer -> GetParameters (
&Maximum_Packet_Size,
&Lower_Layer_Prepend,
&Lower_Layer_Append);
Packet_Pending = NO_PACKET;
Link_Originator = FALSE;
State = NOT_CONNECTED;
Received_Priority = FALSE;
Received_K_Factor = FALSE;
Received_N201 = FALSE;
Received_T200 = FALSE;
DLC_Identifier = 0;
T303_Active = FALSE;
T313_Active = FALSE;
/*
** Get configuration data
*/
T303_Timeout = DEFAULT_T303_TIMEOUT;
T313_Timeout = DEFAULT_T313_TIMEOUT;
Default_Priority = DEFAULT_PRIORITY;
}
/*
* SCFCall::~SCFCall (void)
*
* Public
*
* Functional Description:
* This is the SCFCall destructor. This routine cleans up the mess
*/
SCFCall::~SCFCall (void)
{
if (T303_Active)
{
StopTimerT303 ();
}
if (T313_Active)
{
StopTimerT313 ();
}
}
/*
* SCFCall::ConnectRequest (
* CallReference call_reference,
* DLCI dlci,
* USHORT priority)
*
* Public
*
* Functional Description:
* This function is called when SCF wants to initiate a call.
* As a result, we queue a SETUP command to be sent out.
*/
SCFCallError SCFCall::ConnectRequest(
CallReference call_reference,
DLCI dlci,
TransportPriority priority)
{
TRACE_OUT(("SCFCall::ConnectRequest"));
Call_Reference = call_reference;
DLC_Identifier = dlci;
Priority = priority;
Link_Originator = TRUE;
if (State == NOT_CONNECTED)
Packet_Pending = SETUP;
return (SCFCALL_NO_ERROR);
}
/*
* SCFCallError SCFCall::ConnectResponse (
* BOOL valid_dlci)
*
* Public
*
* Functional Description:
* This function is called in response to a NETWORK_CONNECT_INDICATION
* callback to the owner of this object. Previously, the remote site
* sent us a SETUP packet with a suggested DLCI. This DLCI is sent to
* the owner in the NETWORK_CONNECT_INDICATION call. The owner calls
* this function with a BOOL , telling us if the DLCI was valid.
*/
SCFCallError SCFCall::ConnectResponse (
BOOL valid_dlci)
{
TRACE_OUT(("SCFCall::ConnectResponse"));
if (valid_dlci)
{
/*
** This DLCI can be used in a link. If the remote site did not
** request a priority, we set it to Default_Priority
*/
if (Priority == 0xffff)
Priority = Default_Priority;
Packet_Pending = CONNECT;
}
else
{
/*
** Queue up a RELEASE COMPLETE packet
*/
Packet_Pending = RELEASE_COMPLETE;
Release_Cause = REQUESTED_CHANNEL_UNAVAILABLE;
}
return (SCFCALL_NO_ERROR);
}
/*
* SCFCallError SCFCall::DisconnectRequest ()
*
* Public
*
* Functional Description:
* This function is called when the SCF wants to terminate the call
*/
SCFCallError SCFCall::DisconnectRequest ()
{
TRACE_OUT(("SCFCall::DisconnectRequest"));
/*
** Queue up the Release Complete
*/
if (State != NOT_CONNECTED)
{
Packet_Pending = RELEASE_COMPLETE;
Release_Cause = NORMAL_USER_DISCONNECT;
}
return (SCFCALL_NO_ERROR);
}
/*
* BOOL SCFCall::ProcessSetup (
* CallReference call_reference,
* LPBYTE packet_address,
* USHORT packet_length)
*
* Public
*
* Functional Description:
* This function processes an incoming SETUP packet
*/
BOOL SCFCall::ProcessSetup (
CallReference call_reference,
LPBYTE packet_address,
USHORT packet_length)
{
USHORT length;
BOOL packet_successful;
USHORT remainder_length;
USHORT n201;
USHORT k_factor;
USHORT t200;
NetworkConnectStruct connect_struct;
TRACE_OUT(("SCFCall::ProcessSetup"));
if (State != NOT_CONNECTED)
return (FALSE);
Call_Reference = call_reference;
packet_successful = TRUE;
remainder_length = packet_length;
/*
** Bearer capability element
*/
if (*(packet_address++) != BEARER_CAPABILITY)
return (FALSE);
remainder_length--;
length = *(packet_address++);
remainder_length--;
if (length != 3)
return (FALSE);
/*
** Verify that the Bearer Capability is correct
*/
if (*(packet_address) !=
(EXTENSION | CODING_STANDARD | INFORMATION_TRANSFER_CAPABILITY))
{
return (FALSE);
}
if (*(packet_address + 1) != (EXTENSION | TRANSFER_MODE))
{
return (FALSE);
}
if (*(packet_address + 2) !=
(EXTENSION | LAYER_2_IDENT | USER_INFORMATION_LAYER_2))
{
return (FALSE);
}
packet_address += length;
remainder_length -= length;
/*
** DLCI element
*/
if (*(packet_address++) != DLCI_ELEMENT)
return (FALSE);
remainder_length--;
length = *(packet_address++);
if (length != 2)
return (FALSE);
remainder_length--;
/*
** If the Preferred/Exclusive bit is set, its illegal
*/
if (((*(packet_address) & PREFERRED_EXCLUSIVE) == PREFERRED_EXCLUSIVE) ||
((*(packet_address + 1) & EXTENSION) == 0))
{
return (FALSE);
}
DLC_Identifier = (*(packet_address) & 0x3f) << 4;
DLC_Identifier |= ((*(packet_address + 1) & 0x78) >> 3);
packet_address += length;
remainder_length -= length;
Priority = 0xffff;
/*
** Go thru each of the elements and decode them
*/
while (remainder_length)
{
switch (*(packet_address++))
{
case X213_PRIORITY:
length = *(packet_address++);
remainder_length--;
if (((*(packet_address) & EXTENSION) == 1) ||
((*(packet_address + 1) & EXTENSION) == 0))
{
ERROR_OUT(("SCFCall: ProcessSetup: SETUP packet: Illegal X.213 priority"));
return (FALSE);
}
Priority = (*packet_address & 0x0f);
packet_address += length;
remainder_length -= length;
Received_Priority = TRUE;
break;
case LINK_LAYER_CORE_PARAMETERS:
length = *(packet_address++);
remainder_length -= (length + 1);
while (length)
{
switch (*(packet_address++))
{
case FMIF_SIZE:
/*
** N201 is a Q922 parameter. It is the number of
** maximum information bytes in a packet
*/
n201 =
((*packet_address << 7) |
(*(packet_address + 1) & 0x7f));
if ((*(packet_address+1) & EXTENSION) == EXTENSION)
{
length -= 2;
packet_address += 2;
}
else
{
packet_address += 4;
length -= 4;
}
/*
** If the requested n201 value is less than our
** value, it will be our new N201, otherwise send
** our N201 back as the arbitrated value.
*/
if (n201 < DataLink_Struct.n201)
DataLink_Struct.n201 = n201;
Received_N201 = TRUE;
TRACE_OUT(("SCFCALL: ProcessSetup: n201 = %d", DataLink_Struct.n201));
break;
default:
while ((*(packet_address++) & EXTENSION) == 0)
length--;
length--;
break;
}
length--;
}
break;
case LINK_LAYER_PROTOCOL_PARAMETERS:
length = *(packet_address++);
remainder_length -= (length + 1);
while (length)
{
switch (*(packet_address++))
{
case TRANSMIT_WINDOW_SIZE_IDENTIFIER:
/*
** The Window size is the maximum number of
** outstanding packets at any one time
*/
k_factor = *packet_address & 0x7f;
packet_address++;
length--;
/*
** If the requested k_factor value is less than our
** value, it will be our new k_factor, otherwise
** send our k_factor back as the arbitrated value.
*/
if (k_factor < DataLink_Struct.k_factor)
DataLink_Struct.k_factor = k_factor;
Received_K_Factor = TRUE;
TRACE_OUT(("SCFCALL: ProcessSetup: k_factor = %d", DataLink_Struct.k_factor));
break;
case RETRANSMISSION_TIMER_IDENTIFIER:
/*
** t200 is the timeout value before retransmission
*/
t200 = ((*packet_address << 7) |
(*(packet_address + 1) & 0x7f));
packet_address += 2;
length -= 2;
/*
** If the requested t200 value is too small,
** value, it will be our new T200, otherwise
** send our T200 back as the arbitrated value.
*/
if (t200 > DataLink_Struct.t200)
DataLink_Struct.t200 = t200;
Received_T200 = TRUE;
TRACE_OUT(("SCFCALL: ProcessSetup: t200 = %d", DataLink_Struct.t200));
break;
default:
while ((*(packet_address++) & EXTENSION) == 0)
length--;
length--;
break;
}
length--;
}
break;
case END_TO_END_DELAY:
case CALLING_PARTY_SUBADDRESS:
case CALLED_PARTY_SUBADDRESS:
default:
TRACE_OUT(("SCFCall: ProcessSetup: SETUP packet: Option 0x%x"
"requested, but not supported", *(packet_address-1)));
length = *(packet_address);
packet_address += (length + 1);
remainder_length -= (length + 1);
break;
}
remainder_length--;
}
if (Received_N201 == FALSE)
DataLink_Struct.n201 = DataLink_Struct.default_n201;
if (Received_K_Factor == FALSE)
DataLink_Struct.k_factor = DataLink_Struct.default_k_factor;
if (Received_T200 == FALSE)
DataLink_Struct.t200 = DataLink_Struct.default_t200;
if (packet_successful)
{
/*
** If the packet was successfully decoded, tell the owner the requested
** DLCI and priority.
*/
connect_struct.dlci = DLC_Identifier;
connect_struct.priority = Priority;
connect_struct.datalink_struct = &DataLink_Struct;
/*
** Convert t200 into milliseconds
*/
DataLink_Struct.t200 *= 100;
m_pSCF->OwnerCallback(m_nMsgBase + NETWORK_CONNECT_INDICATION, 0, 0, &connect_struct);
DataLink_Struct.t200 /= 100;
}
return (packet_successful);
}
/*
* BOOL SCFCall::ProcessConnect (
* LPBYTE packet_address,
* USHORT packet_length)
*
* Public
*
* Functional Description:
* This function processes an incoming CONNECT packet
*/
BOOL SCFCall::ProcessConnect (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("SCFCall::ProcessConnect"));
BOOL packet_successful;
USHORT length;
DLCI exclusive_dlci;
USHORT remainder_length;
USHORT k_factor;
USHORT t200;
if (State != SETUP_SENT)
{
ERROR_OUT(("SCFCall: ProcessConnect: Call in wrong state"));
return (FALSE);
}
remainder_length = packet_length;
packet_successful = TRUE;
/*
** DLCI element
*/
if (*(packet_address++) != DLCI_ELEMENT)
{
ERROR_OUT(("SCFCall: ProcessConnect: DLCI_ELEMENT not in packet"));
return (FALSE);
}
remainder_length--;
length = *(packet_address++);
if (length != 2)
{
ERROR_OUT(("SCFCall: ProcessConnect: DLCI length must be 2"));
return (FALSE);
}
remainder_length--;
/*
** If the Preferred/Exclusive bit is not set, its illegal
*/
if (((*(packet_address) & PREFERRED_EXCLUSIVE) == 0) ||
((*(packet_address + 1) & EXTENSION) == 0))
{
ERROR_OUT(("SCFCall: CONNECT: Illegal DLCI"));
return (FALSE);
}
/*
** Get the DLCI
*/
exclusive_dlci = (*(packet_address) & 0x3f) << 4;
exclusive_dlci |= ((*(packet_address + 1) & 0x78) >> 3);
packet_address += length;
remainder_length -= length;
/*
** Go thru each of the elements and decode them
*/
while (remainder_length != 0)
{
switch (*(packet_address++))
{
case X213_PRIORITY:
length = *(packet_address++);
remainder_length--;
if ((*(packet_address) & EXTENSION) == 0)
{
ERROR_OUT(("SCFCall: DataIndication: CONNECT packet: Illegal X.213 priority"));
return (FALSE);
}
Priority = (*packet_address & 0x0f);
packet_address += length;
remainder_length -= length;
break;
case LINK_LAYER_CORE_PARAMETERS:
length = *(packet_address++);
remainder_length -= (length + 1);
while (length)
{
switch (*(packet_address++))
{
case FMIF_SIZE:
/*
** FMIF_Size is the max. number of bytes allowed in
** a information packet
*/
DataLink_Struct.n201 =
((*packet_address << 7) |
(*(packet_address + 1) & 0x7f));
if ((*(packet_address+1) & EXTENSION) == EXTENSION)
{
length -= 2;
packet_address += 2;
}
else
{
packet_address += 4;
length -= 4;
}
Received_N201 = TRUE;
TRACE_OUT(("SCFCALL: ProcessConnect: n201 = %d", DataLink_Struct.n201));
break;
default:
while ((*(packet_address++) & EXTENSION) == 0)
length--;
length--;
break;
}
length--;
}
break;
case LINK_LAYER_PROTOCOL_PARAMETERS:
length = *(packet_address++);
remainder_length -= (length + 1);
while (length)
{
switch (*(packet_address++))
{
case TRANSMIT_WINDOW_SIZE_IDENTIFIER:
/*
** The Window size is the maximum number of
** outstanding packets at any one time
*/
k_factor = *packet_address & 0x7f;
packet_address++;
length--;
DataLink_Struct.k_factor = k_factor;
Received_K_Factor = TRUE;
TRACE_OUT(("SCFCALL: ProcessConnect: k_factor = %d", DataLink_Struct.k_factor));
break;
case RETRANSMISSION_TIMER_IDENTIFIER:
/*
** t200 is the timeout value before retransmission
*/
t200 = ((*packet_address << 7) |
(*(packet_address + 1) & 0x7f));
packet_address += 2;
length -= 2;
DataLink_Struct.t200 = t200;
Received_T200 = TRUE;
TRACE_OUT(("SCFCALL: ProcessConnect: t200 = %d", DataLink_Struct.t200));
break;
default:
while ((*(packet_address++) & EXTENSION) == 0)
length--;
length--;
break;
}
length--;
}
break;
case END_TO_END_DELAY:
case CALLING_PARTY_SUBADDRESS:
case CALLED_PARTY_SUBADDRESS:
default:
TRACE_OUT(("SCFCall: DataIndication: CONNECT packet: Option "
"requested, but not supported", *(packet_address-1)));
length = *(packet_address++);
remainder_length--;
packet_address += length;
remainder_length -= length;
break;
}
remainder_length--;
}
if (Received_N201 == FALSE)
DataLink_Struct.n201 = DataLink_Struct.default_n201;
if (Received_K_Factor == FALSE)
DataLink_Struct.k_factor = DataLink_Struct.default_k_factor;
if (Received_T200 == FALSE)
DataLink_Struct.t200 = DataLink_Struct.default_t200;
/*
** If the packet was successfully decoded, queue up the CONNECT ACK
*/
if (packet_successful)
{
Packet_Pending = CONNECT_ACKNOWLEDGE;
StopTimerT303 ();
}
return (packet_successful);
}
/*
* BOOL SCFCall::ProcessConnectAcknowledge (
* LPBYTE,
* USHORT)
*
* Public
*
* Functional Description:
* This function processes an incoming CONNECT ACK packet
*
*/
BOOL SCFCall::ProcessConnectAcknowledge (
LPBYTE,
USHORT)
{
TRACE_OUT(("SCFCall::ProcessConnectAcknowledge"));
if (State != CONNECT_SENT)
return (FALSE);
StopTimerT313 ();
return (TRUE);
}
/*
* BOOL SCFCall::ProcessReleaseComplete (
* LPBYTE packet_address,
* USHORT)
*
* Public
*
* Functional Description:
* This function processes an incoming RELEASE COMPLETE
*/
BOOL SCFCall::ProcessReleaseComplete (
LPBYTE packet_address,
USHORT)
{
TRACE_OUT(("SCFCall::ProcessReleaseComplete"));
USHORT cause;
if (State == NOT_CONNECTED)
return (FALSE);
if (*(packet_address++) == CAUSE)
{
packet_address++;
if ((*(packet_address++) & EXTENSION) == 0)
packet_address++;
cause = *(packet_address++) & (~EXTENSION);
TRACE_OUT(("SCFCall: Disconnect: cause = %d", cause));
}
State = NOT_CONNECTED;
/*
** Tell the owner about the Disconnection
*/
m_pSCF->OwnerCallback(m_nMsgBase + NETWORK_DISCONNECT_INDICATION,
(void *) DLC_Identifier,
(void *) (ULONG_PTR)(((Link_Originator << 16) | cause)));
return (TRUE);
}
/*
* void SCFCall::PollTransmitter (
* USHORT data_to_transmit,
* USHORT * pending_data);
*
* Public
*
* Functional Description:
* This function is called to transmit any queued up packets
*/
void SCFCall::PollTransmitter (
USHORT data_to_transmit,
USHORT * pending_data)
{
// TRACE_OUT(("SCFCall::PollTransmitter"));
NetworkConnectStruct connect_struct;
if (data_to_transmit & PROTOCOL_CONTROL_DATA)
{
switch (Packet_Pending)
{
case SETUP:
SendSetup ();
break;
case CONNECT:
SendConnect ();
break;
case CONNECT_ACKNOWLEDGE:
SendConnectAcknowledge ();
if (Packet_Pending != CONNECT_ACKNOWLEDGE)
{
/*
** If the CONNECT ACK packet was sent, notify the owner
*/
connect_struct.dlci = DLC_Identifier;
connect_struct.priority = Priority;
connect_struct.datalink_struct = &DataLink_Struct;
/*
** Convert t200 to milliseconds
*/
DataLink_Struct.t200 *= 100;
m_pSCF->OwnerCallback(m_nMsgBase + NETWORK_CONNECT_CONFIRM, 0, 0, &connect_struct);
DataLink_Struct.t200 /= 100;
}
break;
case RELEASE_COMPLETE:
SendReleaseComplete ();
if (Packet_Pending != RELEASE_COMPLETE)
{
/*
** If the RELEASE COMPLETE packet was sent, notify
** the owner
*/
m_pSCF->OwnerCallback(m_nMsgBase + NETWORK_DISCONNECT_INDICATION,
(void *) DLC_Identifier,
(void *) ((((ULONG_PTR) Link_Originator) << 16) | Release_Cause));
}
break;
}
if (Packet_Pending != NO_PACKET)
*pending_data = PROTOCOL_CONTROL_DATA;
else
*pending_data = 0;
}
return;
}
/*
* void SCFCall::SendSetup (void);
*
* Functional Description
* This function attempts to send out a SETUP packet. The T303 timer
* is started. If a CONNECT is not received before the timer expires,
* we terminate the link.
*
* Formal Parameters
* None
*
* Return Value
* None
*
* Side Effects
* If this function is able to send a SETUP packet to the lower layer,
* it sets the Packet_Pending variable to NO_PACKET
*
* Caveats
* None
*/
void SCFCall::SendSetup (void)
{
TRACE_OUT(("SCFCall::SendSetup"));
LPBYTE packet_address;
ULONG bytes_accepted;
USHORT total_length;
PMemory memory;
total_length = SETUP_PACKET_SIZE + Lower_Layer_Prepend +
Lower_Layer_Append;
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
total_length);
if (memory == NULL)
return;
packet_address = memory -> GetPointer ();
packet_address += Lower_Layer_Prepend;
*(packet_address++) = Q931_PROTOCOL_DISCRIMINATOR;
*(packet_address++) = 1;
*(packet_address++) = (UChar) Call_Reference;
*(packet_address++) = SETUP;
/*
** Bearer Capability
*/
*(packet_address++) = BEARER_CAPABILITY;
*(packet_address++) = 3;
*(packet_address++) =
EXTENSION | CODING_STANDARD | INFORMATION_TRANSFER_CAPABILITY;
*(packet_address++) = EXTENSION | TRANSFER_MODE;
*(packet_address++) = EXTENSION | LAYER_2_IDENT | USER_INFORMATION_LAYER_2;
/*
** DLCI
*/
*(packet_address++) = DLCI_ELEMENT;
*(packet_address++) = 2;
*(packet_address++) = (DLC_Identifier >> 4);
*(packet_address++) = EXTENSION | ((DLC_Identifier & 0x0f) << 3);
/*
** Link Layer Core Parameters
*/
*(packet_address++) = LINK_LAYER_CORE_PARAMETERS;
*(packet_address++) = 3;
*(packet_address++) = FMIF_SIZE;
*(packet_address++) = (DataLink_Struct.n201 >> 7);
*(packet_address++) = EXTENSION | (DataLink_Struct.n201 & 0x7f);
/*
** Link Layer Protocol Parameters
*/
*(packet_address++) = LINK_LAYER_PROTOCOL_PARAMETERS;
*(packet_address++) = 5;
*(packet_address++) = TRANSMIT_WINDOW_SIZE_IDENTIFIER;
*(packet_address++) = EXTENSION | DataLink_Struct.k_factor;
*(packet_address++) = RETRANSMISSION_TIMER_IDENTIFIER;
*(packet_address++) = (DataLink_Struct.t200 >> 7) & 0x7f;
*(packet_address++) = EXTENSION | (DataLink_Struct.t200 & 0x7f);
/*
** X.213 Priority
*/
*(packet_address++) = X213_PRIORITY;
*(packet_address++) = 2;
*(packet_address++) = (UChar) Priority;
/*
** The next byte contains the lowest priority acceptable, 0
*/
*(packet_address++) = EXTENSION | 0;
/*
** Attempt to send the packet down
*/
Lower_Layer -> DataRequest (
0,
memory,
&bytes_accepted);
if (bytes_accepted == total_length)
{
T303_Count = 0;
Packet_Pending = NO_PACKET;
State = SETUP_SENT;
StartTimerT303 ();
}
Data_Request_Memory_Manager -> FreeMemory (memory);
}
/*
* void SCFCall::SendConnect (void);
*
* Functional Description
* This function attempts to send out a CONNECT packet. The T313 timer
* is started. If a CONNECT ACK is not received before the timer expires,
* we terminate the link.
*
* Formal Parameters
* None
*
* Return Value
* None
*
* Side Effects
* If this function is able to send a CONNECT packet to the lower layer,
* it sets the Packet_Pending variable to NO_PACKET
*
* Caveats
* None
*
*/
void SCFCall::SendConnect (void)
{
TRACE_OUT(("SCFCall::SendConnect"));
LPBYTE packet_address;
LPBYTE length_address;
ULONG bytes_accepted;
USHORT total_length;
PMemory memory;
total_length = CONNECT_PACKET_BASE_SIZE + Lower_Layer_Prepend +
Lower_Layer_Append;
if (Received_N201)
total_length += 5;
if (Received_K_Factor || Received_T200)
{
total_length += 2;
if (Received_K_Factor)
total_length += 2;
if (Received_T200)
total_length += 3;
}
if (Received_Priority)
total_length += 3;
/*
** Prepare the CONNECT command and send it to the lower layer
*/
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
total_length);
if (memory == NULL)
return;
packet_address = memory -> GetPointer ();
packet_address += Lower_Layer_Prepend;
*(packet_address++) = Q931_PROTOCOL_DISCRIMINATOR;
*(packet_address++) = 1;
*(packet_address++) = REMOTE_CALL_REFERENCE | Call_Reference;
*(packet_address++) = CONNECT;
/*
** DLCI
*/
*(packet_address++) = DLCI_ELEMENT;
*(packet_address++) = 2;
*(packet_address++) = PREFERRED_EXCLUSIVE | (DLC_Identifier >> 4);
*(packet_address++) = EXTENSION | ((DLC_Identifier & 0x0f) << 3);
if (Received_N201)
{
/*
** Link Layer Core Parameters
*/
*(packet_address++) = LINK_LAYER_CORE_PARAMETERS;
*(packet_address++) = 3;
*(packet_address++) = FMIF_SIZE;
*(packet_address++) = (DataLink_Struct.n201 >> 7);
*(packet_address++) = EXTENSION | (DataLink_Struct.n201 & 0x7f);
}
else
DataLink_Struct.n201 = DataLink_Struct.default_n201;
if (Received_K_Factor || Received_T200)
{
/*
** Link Layer Protocol Parameters
*/
*(packet_address++) = LINK_LAYER_PROTOCOL_PARAMETERS;
length_address = packet_address;
*(packet_address++) = 0;
if (Received_K_Factor)
{
*length_address += 2;
*(packet_address++) = TRANSMIT_WINDOW_SIZE_IDENTIFIER;
*(packet_address++) = EXTENSION | DataLink_Struct.k_factor;
}
if (Received_T200)
{
*length_address += 3;
*(packet_address++) = RETRANSMISSION_TIMER_IDENTIFIER;
*(packet_address++) = (DataLink_Struct.t200 >> 7) & 0x7f;
*(packet_address++) = EXTENSION | (DataLink_Struct.t200 & 0x7f);
}
}
if (Received_K_Factor == FALSE)
DataLink_Struct.k_factor = DataLink_Struct.default_k_factor;
if (Received_T200 == FALSE)
DataLink_Struct.t200 = DataLink_Struct.default_t200;
if (Received_Priority)
{
/*
** X.213 Priority
*/
*(packet_address++) = X213_PRIORITY;
*(packet_address++) = 1;
*(packet_address++) = (BYTE) (EXTENSION | Priority);
}
/*
** Attempt to send the packet to the lower layer
*/
Lower_Layer -> DataRequest (
0,
memory,
&bytes_accepted);
if (bytes_accepted == total_length)
{
StartTimerT313 ();
Packet_Pending = NO_PACKET;
State = CONNECT_SENT;
}
Data_Request_Memory_Manager -> FreeMemory (memory);
}
/*
* void SCFCall::SendConnectAcknowledge (void);
*
* Functional Description
* This function attempts to send out a CONNECT ACKNOWLEDGE packet
*
* Formal Parameters
* None
*
* Return Value
* None
*
* Side Effects
* If this function is able to send the packet to the lower layer,
* it sets the Packet_Pending variable to NO_PACKET
*
* Caveats
* None
*
*/
void SCFCall::SendConnectAcknowledge (void)
{
TRACE_OUT(("SCFCall::SendConnectAcknowledge"));
LPBYTE packet_address;
USHORT total_length;
PMemory memory;
ULONG bytes_accepted;
total_length = CONNECT_ACK_PACKET_SIZE + Lower_Layer_Prepend +
Lower_Layer_Append;
/*
** Prepare the command and send it to the lower layer
*/
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
total_length);
if (memory == NULL)
return;
packet_address = memory -> GetPointer ();
packet_address += Lower_Layer_Prepend;
*(packet_address++) = Q931_PROTOCOL_DISCRIMINATOR;
*(packet_address++) = 1;
*(packet_address++) = (UChar) Call_Reference;
*(packet_address++) = CONNECT_ACKNOWLEDGE;
Lower_Layer -> DataRequest (
0,
memory,
&bytes_accepted);
if (bytes_accepted == total_length)
{
State = CALL_ESTABLISHED;
Packet_Pending = NO_PACKET;
}
Data_Request_Memory_Manager -> FreeMemory (memory);
}
/*
* void SCFCall::SendReleaseComplete (void);
*
* Functional Description
* This function attempts to send out a RELEASE COMPLETE packet
*
* Formal Parameters
* None
*
* Return Value
* None
*
* Side Effects
* If this function is able to send a RELEASE COMPLETE packet to the lower
* layer, it sets the Packet_Pending variable to NO_PACKET
*
* Caveats
* None
*
*/
void SCFCall::SendReleaseComplete (void)
{
TRACE_OUT(("SCFCall::SendReleaseComplete"));
LPBYTE packet_address;
ULONG bytes_accepted;
USHORT total_length;
PMemory memory;
total_length = RELEASE_COMPLETE_PACKET_SIZE + Lower_Layer_Prepend +
Lower_Layer_Append;
/*
** Prepare the command and send it to the lower layer
*/
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
total_length);
if (memory == NULL)
return;
packet_address = memory -> GetPointer ();
packet_address += Lower_Layer_Prepend;
*(packet_address++) = Q931_PROTOCOL_DISCRIMINATOR;
*(packet_address++) = 1;
if (Link_Originator)
*(packet_address++) = (UChar) Call_Reference;
else
*(packet_address++) = 0x80 | Call_Reference;
*(packet_address++) = RELEASE_COMPLETE;
/*
** Append the CAUSE for the link breakup
*/
*(packet_address++) = CAUSE;
*(packet_address++) = 2;
*(packet_address++) = EXTENSION;
*(packet_address++) = EXTENSION | Release_Cause;
Lower_Layer -> DataRequest (
0,
memory,
&bytes_accepted);
if (bytes_accepted == total_length)
{
State = NOT_CONNECTED;
Packet_Pending = NO_PACKET;
}
Data_Request_Memory_Manager -> FreeMemory (memory);
}
/*
* void SCFCall::StartTimerT303 (void);
*
* Functional Description
* This function Starts the T303 Timer. This is started when we send
* out the SETUP packet. It is stopped when we receive a CONNECT
* packet. If it expires we terminate the link.
*
* Formal Parameters
* None
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*
*/
void SCFCall::StartTimerT303 (void)
{
TRACE_OUT(("SCFCall::StartTimerT303"));
if (T303_Active)
StopTimerT303 ();
T303_Handle = g_pSystemTimer->CreateTimerEvent(
T303_Timeout,
TIMER_EVENT_ONE_SHOT,
this,
(PTimerFunction) &SCFCall::T303Timeout);
T303_Active = TRUE;
}
/*
* void SCFCall::StopTimerT303 (void);
*
* Functional Description
* This function stops the T303 Timer. This is called when we receive
* the CONNECT packet. As a result, we stop the timer.
*
* Formal Parameters
* None
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*
*/
void SCFCall::StopTimerT303 (void)
{
TRACE_OUT(("SCFCall::StopTimerT303"));
if (T303_Active)
{
g_pSystemTimer->DeleteTimerEvent(T303_Handle);
T303_Active = FALSE;
}
}
/*
* void SCFCall::T303Timeout (
* TimerEventHandle);
*
* Functional Description
* This function is called by the System timer when the T303 timeout
* expires. As a result, we terminate the link.
*
* Formal Parameters
* None used
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*
*/
void SCFCall::T303Timeout (
TimerEventHandle)
{
TRACE_OUT(("SCFCall: T303Timeout"));
if (T303_Count >= 1)
State = NOT_CONNECTED;
T303_Count++;
Packet_Pending = RELEASE_COMPLETE;
Release_Cause = NORMAL_USER_DISCONNECT;
}
/*
* void SCFCall::StartTimerT313 (void);
*
* Functional Description
* This function Starts the T313 Timer. This is started when we send
* out the CONNECT packet. It is stopped when we receive a CONNECT ACK
* packet. If it expires we terminate the link.
*
* Formal Parameters
* None
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*
*/
void SCFCall::StartTimerT313 (void)
{
TRACE_OUT(("SCFCall: StartTimerT313"));
if (T313_Active)
StopTimerT313 ();
T313_Handle = g_pSystemTimer->CreateTimerEvent(
T313_Timeout,
TIMER_EVENT_ONE_SHOT,
this,
(PTimerFunction) &SCFCall::T313Timeout);
T313_Active = TRUE;
}
/*
* void SCFCall::StopTimerT313 (void);
*
* Functional Description
* This function stops the T313 Timer. This is called when we receive
* the CONNECT ACK packet. As a result, we stop the timer.
*
* Formal Parameters
* None
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*
*/
void SCFCall::StopTimerT313 (void)
{
TRACE_OUT(("SCFCall: StopTimerT313"));
if (T313_Active)
{
g_pSystemTimer->DeleteTimerEvent(T313_Handle);
T313_Active = FALSE;
}
}
/*
* void SCFCall::T313Timeout (
* TimerEventHandle);
*
* Functional Description
* This function is called by the System timer when the T313 timeout
* expires. As a result, we terminate the link.
*
* Formal Parameters
* None used
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*
*/
void SCFCall::T313Timeout (
TimerEventHandle)
{
TRACE_OUT(("SCFCall: T313Timeout"));
State = NOT_CONNECTED;
Packet_Pending = RELEASE_COMPLETE;
Release_Cause = NORMAL_USER_DISCONNECT;
}