Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

3132 lines
99 KiB

#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_T123PSTN);
/* Q922.cpp
*
* Copyright (c) 1993-1995 by DataBeam Corporation, Lexington, KY
*
* Abstract:
* This is the implementation file for the Q.922 Data Link protocol.
* Before diving into the code, it is recommended that you read the
* Q.922 protocol.
*
* Private Instance Variables:
* m_pT123 - Address of the owner of this object. Used for
* owner callbacks.
* m_pMultiplexer - Address of ProtocolLayer below Q922 in the
* stack.
* Higher_Layer - Address of ProtocolLayer above Q922 in the
* stack.
* m_nMsgBase - Message base used in owner callbacks.
* DLCI - DLCI used to identfy Q922 entities.
* Link_Originator - TRUE if we are the link originators. If we are,
* we sent out the first SABME packet.
* Maximum_Information_Size-
* Holds the maximum packet size that we support.
* SABME_Pending - TRUE if we need to initiate the link.
* Unnumbered_Acknowledge_Pending - TRUE if we need to send out an
* Unnumbered Ack. packet. This is
* done in response to a SABME or DISC.
* DISC_Pending - TRUE if we need to send out a DISConnect packet.
* Unnumbered_PF_State - Holds the Poll/Final state of an unnumbered
* packet.
* Final_Packet - TRUE if the next Unnumbered Ack. sent out is
* our final packet to transmit before notifying
* the owner that the link is broken.
* Data_Indication_Size- Number of data indication buffers available
* Data_Indication - Base address of data indication buffers
* Data_Indication_Head- Head of data indication queue
* Data_Indication_Tail- Tail of read data indication queue
* Data_Indication_Count- Number of data indication buffers in use
*
* Data_Request_Size - Number of data request buffers
* Data_Request_Total_Size - Number of data request buffers + maximum
* number of outstanding packets
* Data_Request - Base address of data request buffers
* Data_Request_Head - Head of data request queue
* Data_Request_Tail - Tail of data request queue
* Data_Request_Count - Number of data request buffers in use
* Data_Request_Acknowledge_Tail- Tail of the queue referring to packets
* that have been acknowledged
*
* Supervisory_Write_Struct - Buffer used for supervisory packets
* Send_State_Variable - This is the sequence number that will
* be sent in the next information packet
* to uniquely identify the packet. The
* number is between 0 and 127.
* Receive_State_Variable - Receive Sequence Number. The expected
* sequence number of the next Information
* packet we receive
* Acknowledge_State_Variable - This is the sequence number that the
* remote site is expecting in our next
* information packet
* Own_Receiver_Busy - If our read buffers are full, we set
* this flag so that we send a Receiver
* Not Ready packet to the remote site
* Peer_Receiver_Busy - Remote site is not ready to receive
* Information packets
*
* Command_Pending - When this flag is set to TRUE, we send
* a Supervisory/Command packet to the
* remote site.
*
* We need to send a Supervisory/Command
* packet when our receiver is no longer
* busy. This tells the remote site to
* resume sending Information packets to
* us.
* Poll_Pending - This flag tells us to send a Supervisory
* command to the remote location with the
* Poll flag set. This tells the remote
* site to reply to this command
* Final_Pending - This flag is set when we need to reply
* to a remote command
* Acknowledge_Pending - This flag signals us to send a
* Supervisory/Response packet to the
* remote site.
* Reject_Pending - Signals us to send a Supervisory/
* Response packet to the remote site
* indicating that we missed a packet.
* Reject_Outstanding - Internal flag telling us that our Reject
* packet has been sent and don't send
* another one
* T200_Timeout - Timeout value. If we send out a packet
* and expect a response, and T200_Timeout
* expires, we enter the TIMER_RECOVERY
* mode.
* T200_Handle - Handle to timer event.
* T200_Active - Flag that signals if T200 is running
* N200_Count - Number of times T200 expires in a row
* without a response from the remote site.
*
* T203_Timeout - Timeout value. If we don't receive a
* packet from the remote site in T203
* time, we enter the TIMER_RECOVERY mode.
* T203_Handle - Handle to timer event
* T203_Active - Flag that signals if T203 is running.
* Maximum_T200_Timeouts - Maximum number of T200 timeouts before
* we consider the link unstable.
* Data_Link_Mode - Our mode of operation.
* MULTIPLE_FRAME_ESTABLISHED
* TIMER_RECOVERY
* Link_Stable - Flag that indicates if our current
* connection is stable. FALSE if the
* N200_Count == Maximum number of T200
* timeouts
* Receive_Sequence_Exception - Set if we receive an ILLEGAL sequence
* number
* Maximum_Outstanding_Packets - Maximum number of packets that we can
* have out on the line at a time.
* Outstanding_Packets - Actual number of packets outstanding
* Maximum_Outstanding_Bytes - Maximum number of bytes that can be
* on the line at any one time. It is VERY
* important to note that using this as a
* limiting factor on transmission is NOT
* a protocol defined limit. This was
* added to our Q922 because we had
* problems with some modems that were
* buffering our Tx data. Some modems
* would buffer up to 4K of data. This is
* unacceptable to us because our timeouts
* would expire before the data left the
* modem. Using this parameter as a
* limiting factor validates our timer
* values.
* Outstanding_Bytes - Actual number of bytes on the line at
* the current time.
* Total_Retransmitted - Number of packets that have been
* retransmitted.
* Data_Request_Memory_Manager - Memory manager used for all DataRequests
* Lower_Layer_Prepend - Number of bytes prepended to each packet
* by the lower layer
* Lower_Layer_Append - Number of bytes appended to packet by
* the lower layer.
*
* Caveats:
* None.
*
* Authors:
* James P. Galvin
* James W. Lawwill
*/
#include "q922.h"
/*
* CLayerQ922::CLayerQ922 (
* PTransportResources transport_resources,
* IObject * owner_object,
* IProtocolLayer * lower_layer,
* USHORT message_base,
* USHORT identifier,
* BOOL link_originator,
* USHORT data_indication_queue_siz,
* USHORT data_request_queue_size,
* USHORT k_factor,
* USHORT max_information_size,
* USHORT t200,
* USHORT call_control_type,
* USHORT max_outstanding_bytes,
* PMemoryManager memory_manager,
* BOOL * initialized)
*
* Public
*
* Functional Description:
* This is the CLayerQ922 constructor. This routine initializes all
* variables and allocates buffer space.
*/
CLayerQ922::CLayerQ922
(
T123 *owner_object,
Multiplexer *pMux, // lower layer
USHORT message_base,
USHORT identifier,
BOOL link_originator,
USHORT data_indication_queue_size,
USHORT data_request_queue_size,
USHORT k_factor,
USHORT max_information_size,
USHORT t200,
USHORT max_outstanding_bytes,
PMemoryManager memory_manager,
PLUGXPRT_PSTN_CALL_CONTROL call_control_type,
PLUGXPRT_PARAMETERS *pParams,
BOOL * initialized
)
:
m_pT123(owner_object),
m_nMsgBase(message_base),
m_pMultiplexer(pMux)
{
TRACE_OUT(("CLayerQ922::CLayerQ922"));
ProtocolLayerError error;
USHORT packet_size;
USHORT i;
DLCI = identifier;
Link_Originator = link_originator;
Maximum_Outstanding_Packets = k_factor;
T200_Timeout = t200;
Maximum_Information_Size = max_information_size;
Maximum_Outstanding_Bytes = max_outstanding_bytes;
Data_Request_Memory_Manager = memory_manager;
Higher_Layer = NULL;
Data_Request = NULL;
Data_Indication = NULL;
Data_Indication_Buffer = NULL;
*initialized = TRUE;
/*
** Find the maximum packet size supported by the lower layer
*/
m_pMultiplexer->GetParameters(
&packet_size,
&Lower_Layer_Prepend,
&Lower_Layer_Append);
if (Maximum_Information_Size > packet_size)
Maximum_Information_Size = packet_size;
TRACE_OUT(("Q922: DLCI %d: Max information Size = %d", DLCI, Maximum_Information_Size));
/*
** Register with the lower layer
*/
error = m_pMultiplexer->RegisterHigherLayer(
identifier,
Data_Request_Memory_Manager,
(IProtocolLayer *) this);
if (error != PROTOCOL_LAYER_NO_ERROR)
{
*initialized = FALSE;
ERROR_OUT(("Q922: DLCI %d: constructor: Error registering with lower layer", DLCI));
}
/*
** Allocation of data indication buffers. Allocate the prescribed number
*/
Data_Indication_Size = data_indication_queue_size;
Data_Indication =
(PDataQueue) LocalAlloc (LMEM_FIXED, (sizeof (DataQueue) * Data_Indication_Size));
if (Data_Indication != NULL)
{
Data_Indication_Buffer = (LPBYTE)
LocalAlloc (LMEM_FIXED, Maximum_Information_Size * Data_Indication_Size);
if (Data_Indication_Buffer != NULL)
{
for (i=0; i<Data_Indication_Size; i++)
{
(Data_Indication + i) -> buffer_address =
Data_Indication_Buffer + (i * Maximum_Information_Size);
(Data_Indication + i) -> length = 0;
}
}
else
*initialized = FALSE;
}
else
*initialized = FALSE;
/*
** Allocation of data request buffers. Allocate enough buffers for
** outstanding buffers as well as the buffers queued for delivery.
*/
Data_Request_Size = data_request_queue_size;
Data_Request_Total_Size = Data_Request_Size + Maximum_Outstanding_Packets;
Data_Request = (PMemory *)
LocalAlloc (LMEM_FIXED, (sizeof (PMemory) * Data_Request_Total_Size));
if (Data_Request == NULL)
*initialized = FALSE;
/*
** Allocate one buffer for Supervisory data
*/
T200_Active = FALSE;
T203_Active = FALSE;
/*
** These veriables need to be set to 0 before we call Reset(). Reset()
** will attempt to free any memory block that are in the Data_Request
** list. Since we are just initializing and there aren't any memory
** blocks in the array, there aren't any to release.
*/
Data_Request_Head = 0;
Data_Request_Tail = 0;
Data_Request_Count = 0;
Data_Request_Acknowledge_Tail = 0;
Reset ();
T203_Timeout = (call_control_type == PLUGXPRT_PSTN_CALL_CONTROL_MANUAL) ?
DEFAULT_T203_COMM_TIMEOUT : DEFAULT_T203_TIMEOUT;
Startup_Maximum_T200_Timeouts = DEFAULT_MAXIMUM_T200_TIMEOUTS;
if (NULL != pParams)
{
if (PSTN_PARAM__MAX_T200_TIMEOUT_COUNT_IN_Q922 & pParams->dwFlags)
{
if (Startup_Maximum_T200_Timeouts <= pParams->cMaximumT200TimeoutsInQ922)
{
Startup_Maximum_T200_Timeouts = pParams->cMaximumT200TimeoutsInQ922;
}
}
if (PSTN_PARAM__T203_TIMEOUT_IN_Q922 & pParams->dwFlags)
{
if (T203_Timeout <= pParams->nT203TimeoutInQ922)
{
T203_Timeout = pParams->nT203TimeoutInQ922;
}
}
}
#if 0
DWORD dwSiz = 4;
DWORD valType = 0;
HKEY hkey;
// If we are using null modem.
if(call_control_type == PLUGXPRT_PSTN_CALL_CONTROL_MANUAL)
{
//
// Open the registry key that contains the configuration info for number of timeouts
//
if (RegOpenKey( HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Conferencing\\Transports\\DIRCB\0", &hkey) == ERROR_SUCCESS)
{
if (RegQueryValueEx(hkey, "nTimeouts\0", 0, &valType,
(LPBYTE)&Startup_Maximum_T200_Timeouts, &dwSiz) != ERROR_SUCCESS || Startup_Maximum_T200_Timeouts < DEFAULT_MAXIMUM_T200_TIMEOUTS)
{
Startup_Maximum_T200_Timeouts = DEFAULT_MAXIMUM_T200_TIMEOUTS;
}
RegCloseKey(hkey);
}
}
#endif
Link_Maximum_T200_Timeouts = Startup_Maximum_T200_Timeouts;
Maximum_T200_Timeouts = Startup_Maximum_T200_Timeouts;
/*
** If I am the link originator, enter the AWAITING_ESTABLISHMENT mode and
** send out the SABME packet.
*/
if (Link_Originator)
{
SABME_Pending = TRUE;
Unnumbered_PF_State = UNNUMBERED_PF_SET;
Data_Link_Mode = AWAITING_ESTABLISHMENT;
}
else
{
/*
** If we are not the link originator, enter the TEI_ASSIGNED mode and
** start the T203 timer, if we don't receive a packet in X seconds,
** abort the operation
*/
Data_Link_Mode = TEI_ASSIGNED;
SABME_Pending = FALSE;
StartTimerT203 ();
}
if (*initialized == FALSE)
{
ERROR_OUT(("Q922: DLCI %d: Init failed", DLCI));
}
}
/*
* CLayerQ922::~CLayerQ922 (void)
*
* Public
*
* Functional Description:
* This is the CLayerQ922 destructor. This routine cleans up the mess.
*/
CLayerQ922::~CLayerQ922(void)
{
TRACE_OUT(("CLayerQ922::~CLayerQ922"));
BOOL queue_full;
PMemory memory;
TRACE_OUT(("Q922: Destructor: DLCI = %d Receive_Sequence_Exception = %d",
DLCI, Receive_Sequence_Exception));
TRACE_OUT(("Q922: Destructor: DLCI = %d Receive_Sequence_Recovery = %d",
DLCI, Receive_Sequence_Recovery));
m_pMultiplexer->RemoveHigherLayer (DLCI);
StopTimerT200 ();
StopTimerT203 ();
if (Data_Indication != NULL)
LocalFree ((HLOCAL) Data_Indication);
if (Data_Indication_Buffer != NULL)
LocalFree ((HLOCAL) Data_Indication_Buffer);
if (Data_Request != NULL)
{
/*
** Data_Request_Head is the head of the list,
** Data_Request_Acknowledge_Tail is the absolute tail of the list.
** If the list is full, Data_Request_Head equals
** Data_Request_Acknowledge_Tail. Therefore, we have to check
** Data_Request_Count to see if it is full or empty.
*/
if ((Data_Request_Head == Data_Request_Acknowledge_Tail) &&
(Data_Request_Count != 0))
{
queue_full = TRUE;
}
else
queue_full = FALSE;
/*
** We have to unlock any memory blocks that are in use
*/
while ((Data_Request_Head != Data_Request_Acknowledge_Tail) || queue_full)
{
memory = *(Data_Request + Data_Request_Acknowledge_Tail);
Data_Request_Memory_Manager -> UnlockMemory (memory);
if (++Data_Request_Acknowledge_Tail == Data_Request_Total_Size)
{
Data_Request_Acknowledge_Tail = 0;
}
if (queue_full)
{
queue_full = FALSE;
}
}
LocalFree ((HLOCAL) Data_Request);
}
}
/*
* CLayerQ922::Reset (void)
*
* Functional Description:
* This function resets the link state variables.
*
* Formal Parameters
* None
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::Reset (void)
{
TRACE_OUT(("CLayerQ922::Reset"));
BOOL queue_full;
PMemory memory;
Data_Indication_Head = 0;
Data_Indication_Tail = 0;
Data_Indication_Count = 0;
/*
** Data_Request_Head is the head of the list,
** Data_Request_Acknowledge_Tail is the absolute tail of the list.
** If the list is full, Data_Request_Head equals
** Data_Request_Acknowledge_Tail. Therefore, we have to check
** Data_Request_Count to see if it is full or empty.
*/
if ((Data_Request_Head == Data_Request_Acknowledge_Tail) &&
(Data_Request_Count != 0))
{
queue_full = TRUE;
}
else
queue_full = FALSE;
/*
** We have to unlock any memory blocks that are in use
*/
while ((Data_Request_Head != Data_Request_Acknowledge_Tail) || queue_full)
{
memory = *(Data_Request + Data_Request_Acknowledge_Tail);
Data_Request_Memory_Manager -> UnlockMemory (memory);
if (++Data_Request_Acknowledge_Tail == Data_Request_Total_Size)
Data_Request_Acknowledge_Tail = 0;
if (queue_full)
{
queue_full = FALSE;
}
}
Data_Request_Head = 0;
Data_Request_Tail = 0;
Data_Request_Count = 0;
Data_Request_Acknowledge_Tail = 0;
Outstanding_Packets = 0;
Outstanding_Bytes = 0;
Total_Retransmitted = 0;
Send_State_Variable = 0;
Receive_State_Variable = 0;
Acknowledge_State_Variable = 0;
Own_Receiver_Busy = FALSE;
Peer_Receiver_Busy = FALSE;
Command_Pending = FALSE;
Poll_Pending = FALSE;
Final_Pending = FALSE;
Acknowledge_Pending = FALSE;
Reject_Pending = FALSE;
Reject_Outstanding = FALSE;
SABME_Pending = FALSE;
Frame_Reject_Pending = FALSE;
Unnumbered_Acknowledge_Pending = FALSE;
DISC_Pending = FALSE;
Final_Packet = FALSE;
Disconnected_Mode_Pending = FALSE;
N200_Count = 0;
Link_Stable = TRUE;
Receive_Sequence_Exception = 0;
Receive_Sequence_Recovery = 0;
StopTimerT200 ();
StopTimerT203 ();
}
/*
* DataLinkError CLayerQ922::ReleaseRequest (void)
*
* Public
*
* Functional Description:
* This function sets the necessary flags to terminate the link
*/
DataLinkError CLayerQ922::ReleaseRequest (void)
{
TRACE_OUT(("CLayerQ922::ReleaseRequest"));
if ((Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED) ||
(Data_Link_Mode == TIMER_RECOVERY))
{
/*
** Queue up the DISC_Pending flag to send out a DISC packet
*/
DISC_Pending = TRUE;
Unnumbered_PF_State = UNNUMBERED_PF_SET;
Data_Link_Mode = AWAITING_RELEASE;
StopTimerT200 ();
StopTimerT203 ();
}
else
{
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_CONFIRM,
(void *) DLCI, (void *) DATALINK_NORMAL_DISCONNECT);
}
return (DATALINK_NO_ERROR);
}
/*
* DataLinkError CLayerQ922::DataIndication (
* LPBYTE packet_address,
* ULONG buffer_size,
* PULong packet_length)
*
* Public
*
* Functional Description:
* This function is called by the lower layer when it has a packet to
* pass to us.
*/
ProtocolLayerError CLayerQ922::DataIndication (
LPBYTE packet_address,
ULONG packet_length,
PULong bytes_accepted)
{
TRACE_OUT(("CLayerQ922::DataIndication"));
BOOL packet_processed = TRUE;
/*
** The packet MUST be at least UNNUMBERED_HEADER_SIZE or it is
** invalid
*/
if (packet_length < UNNUMBERED_HEADER_SIZE)
{
*bytes_accepted = packet_length;
return (PROTOCOL_LAYER_NO_ERROR);
}
if (*(packet_address + CONTROL_BYTE_HIGH) & SUPERVISORY_FRAME_BIT)
{
if (*(packet_address + CONTROL_BYTE_HIGH) & UNNUMBERED_FRAME_BIT)
{
/*
** This packet is an unnumbered packet
*/
switch (*(packet_address + CONTROL_BYTE_HIGH) &
UNNUMBERED_COMMAND_MASK)
{
case SABME:
ProcessSABME (
packet_address,
(USHORT) packet_length);
break;
case UNNUMBERED_ACKNOWLEDGE:
ProcessUnnumberedAcknowledge (
packet_address,
(USHORT) packet_length);
break;
case FRAME_REJECT:
ProcessFrameReject (
packet_address,
(USHORT) packet_length);
break;
case DISCONNECTED_MODE:
ProcessDisconnectMode (
packet_address,
(USHORT) packet_length);
break;
case DISC:
ProcessDISC (
packet_address,
(USHORT) packet_length);
break;
default:
ERROR_OUT(("Q922: DLCI %d: DataIndication: Illegal Packet: = %d",
DLCI, (*(packet_address + CONTROL_BYTE_HIGH) & UNNUMBERED_COMMAND_MASK)));
break;
}
}
else
{
/*
** It is only legal to process supervisory frames if we
** are in the MULTIPLE_FRAME_ESTABLISHED or TIMER_RECOVERY
** modes
*/
if ((Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED) ||
(Data_Link_Mode == TIMER_RECOVERY))
{
switch (*(packet_address + CONTROL_BYTE_HIGH) &
SUPERVISORY_COMMAND_MASK)
{
case RECEIVER_READY:
ProcessReceiverReady (
packet_address,
(USHORT) packet_length);
break;
case RECEIVER_NOT_READY:
ProcessReceiverNotReady (
packet_address,
(USHORT) packet_length);
break;
case REJECT:
ProcessReject (
packet_address,
(USHORT) packet_length);
break;
}
}
else
{
ERROR_OUT(("Q922: DLCI %d: Supervisory packet received in illegal DataLink Mode", DLCI));
#ifdef _MCATIPX
if (Data_Link_Mode != AWAITING_RELEASE)
{
/*
** This is necessary on an IPX network to notify the remote
** site that this unit is no longer in the conference. If
** the previous conference ended without going through the
** proper disconnect sequence, the remote site may continue
** to send frames to this site. In which case, we need to
** notify the remote site that the conference is no longer
** active. We are doing this by sending out a DISC frame.
** The Q.921 specification does not address this situation.
*/
DISC_Pending = TRUE;
Unnumbered_PF_State = UNNUMBERED_PF_RESET;
}
#endif
}
}
}
else
{
/*
** It is only legal to process Information frames if we
** are in the MULTIPLE_FRAME_ESTABLISHED or TIMER_RECOVERY
** modes
*/
if ((Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED) ||
(Data_Link_Mode == TIMER_RECOVERY))
{
packet_processed = ProcessInformationFrame (
packet_address,
(USHORT) packet_length);
}
else
{
ERROR_OUT(("Q922: DLCI %d: Information packet received in illegal DataLink Mode", DLCI));
#ifdef _MCATIPX
if (Data_Link_Mode != AWAITING_RELEASE)
{
/*
** This is necessary on an IPX network to notify the remote
** site that this unit is no longer in the conference. If
** the previous conference ended without going through the
** proper disconnect sequence, the remote site may continue
** to send frames to this site. In which case, we need to
** notify the remote site that the conference is no longer
** active. We are doing this by sending out a DISC frame.
** The Q.921 specification does not address this situation.
*/
DISC_Pending = TRUE;
Unnumbered_PF_State = UNNUMBERED_PF_RESET;
}
#endif
}
}
/*
** After we receive a packet we should start the T203 timer
** unless the T200 timer was started during the processing of
** the packet
*/
if (((Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED) ||
(Data_Link_Mode == TIMER_RECOVERY)) &&
(T200_Active == FALSE) &&
(DLCI == 0))
{
StartTimerT203 ();
}
if (packet_processed)
{
if ((Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED) ||
(Data_Link_Mode == TIMER_RECOVERY))
{
N200_Count = 0;
}
*bytes_accepted = packet_length;
}
else
*bytes_accepted = 0;
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* ProtocolLayerError CLayerQ922::PollTransmitter (
* ULONG,
* USHORT data_to_transmit,
* USHORT * pending_data,
* USHORT * holding_data);
*
* Public
*
* Functional Description:
* This function is called to give us a chance to transmit packets.
* The data_to_transmit mask tells us which data to transmit, either
* control or user data.
*/
ProtocolLayerError CLayerQ922::PollTransmitter (
ULONG_PTR,
USHORT data_to_transmit,
USHORT * pending_data,
USHORT * holding_data)
{
// TRACE_OUT(("CLayerQ922::PollTransmitter"));
*pending_data = 0;
/*
** If we are permitted to transmit data, call ProcessWriteQueue ()
*/
if ((data_to_transmit & PROTOCOL_CONTROL_DATA) ||
(data_to_transmit & PROTOCOL_USER_DATA))
{
ProcessWriteQueue (data_to_transmit);
}
/*
** We have to set the pending data variable to reflect which data
** we still need to send out
*/
if (Data_Request_Count != 0)
*pending_data |= PROTOCOL_USER_DATA;
if (Poll_Pending || Final_Pending || Command_Pending ||
(Reject_Pending && (Own_Receiver_Busy == FALSE)) ||
Acknowledge_Pending || SABME_Pending ||
Unnumbered_Acknowledge_Pending || Frame_Reject_Pending ||
DISC_Pending)
{
*pending_data |= PROTOCOL_CONTROL_DATA;
}
*holding_data = Outstanding_Packets;
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* DataLinkError CLayerQ922::DataRequest (
* ULONG,
* PMemory memory,
* PULong bytes_accepted)
*
* Public
*
* Functional Description:
* This function is called by the higher layer to send a packet to the
* remote site.
*/
ProtocolLayerError CLayerQ922::DataRequest (
ULONG_PTR,
PMemory memory,
PULong bytes_accepted)
{
TRACE_OUT(("CLayerQ922::DataRequest"));
PMemory * data_request;
USHORT trash_word;
ULONG packet_length;
ULONG information_size;
*bytes_accepted = 0;
packet_length = memory -> GetLength ();
/*
** Determine the actual information length
*/
information_size =
packet_length - Lower_Layer_Prepend -
Lower_Layer_Append - DATALINK_PACKET_OVERHEAD;
/*
** See if the information content is too big.
*/
if (information_size > Maximum_Information_Size)
{
TRACE_OUT(("Q922: DLCI %d: DataRequest: Requested packet = %d, max = %d",
DLCI, information_size, Maximum_Information_Size));
return (PROTOCOL_LAYER_PACKET_TOO_BIG);
}
if (Data_Request_Count < Data_Request_Size)
{
/*
** Set write_queue to the correct location
*/
data_request = Data_Request + Data_Request_Head;
*data_request = memory;
/*
** Lock the memory object so that it won't be released
*/
Data_Request_Memory_Manager -> LockMemory (memory);
if (++Data_Request_Head == Data_Request_Total_Size)
Data_Request_Head = 0;
Data_Request_Count++;
*bytes_accepted = packet_length;
/*
** If the higher layer got permission to send data to me, I will
** attempt to send it on out
*/
PollTransmitter (
0,
PROTOCOL_USER_DATA | PROTOCOL_CONTROL_DATA,
&trash_word,
&trash_word);
}
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* DataLinkError CLayerQ922::DataRequest (
* ULONG,
* PMemory memory,
* PULong bytes_accepted)
*
* Public
*
* Functional Description:
* This function is called by the higher layer to send a packet to the
* remote site. This type of data passing is NOT supported by this
* layer.
*/
ProtocolLayerError CLayerQ922::DataRequest (
ULONG_PTR,
LPBYTE,
ULONG,
PULong bytes_accepted)
{
*bytes_accepted = 0;
return (PROTOCOL_LAYER_ERROR);
}
/*
* ProtocolLayerError CLayerQ922::PollReceiver (
* ULONG)
*
* Public
*
* Functional Description
* This function is called to give us a chance to send packets to the
* higher layer
*/
ProtocolLayerError CLayerQ922::PollReceiver(void)
{
ULONG bytes_accepted;
PDataQueue data_indication;
/*
** If I have any packet in my receive buffers that
** need to go to higher layers, send them now
*/
while (Data_Indication_Count != 0)
{
data_indication = Data_Indication + Data_Indication_Tail;
if (Higher_Layer == NULL)
break;
Higher_Layer -> DataIndication (
data_indication -> buffer_address,
data_indication -> length,
&bytes_accepted);
if (bytes_accepted == (data_indication -> length))
{
if (++Data_Indication_Tail == Data_Indication_Size)
Data_Indication_Tail = 0;
Data_Indication_Count--;
/*
** If we had been in a Receiver Busy mode, exit it
*/
if (Own_Receiver_Busy)
{
Own_Receiver_Busy = FALSE;
Command_Pending = TRUE;
}
}
else
break;
}
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* void CLayerQ922::ProcessWriteQueue (
* USHORT data_to_transmit)
*
* Functional Description
* This function determines which type of data needs to be sent out, and
* sends it.
*
* Formal Parameters
* data_to_transmit (i) - Mask telling us which data is allowed to be
* transmitted
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::ProcessWriteQueue (
USHORT data_to_transmit)
{
// TRACE_OUT(("CLayerQ922::ProcessWriteQueue"));
BOOL continue_loop = TRUE;
while (continue_loop)
{
switch (Data_Link_Mode)
{
case AWAITING_RELEASE:
case TEI_ASSIGNED:
case AWAITING_ESTABLISHMENT:
if (SABME_Pending || DISC_Pending || Unnumbered_Acknowledge_Pending ||
Disconnected_Mode_Pending || Frame_Reject_Pending)
{
continue_loop = TransmitUnnumberedFrame ();
}
else
{
continue_loop = FALSE;
}
break;
default:
if (Poll_Pending)
{
continue_loop = TransmitSupervisoryFrame (COMMAND_FRAME, PF_SET);
}
else if (Final_Pending)
{
continue_loop = TransmitSupervisoryFrame (RESPONSE_FRAME, PF_SET);
}
else if (Command_Pending)
{
continue_loop = TransmitSupervisoryFrame (COMMAND_FRAME, PF_RESET);
}
else if (Reject_Pending && (Own_Receiver_Busy == FALSE))
{
continue_loop = TransmitSupervisoryFrame (RESPONSE_FRAME, PF_RESET);
}
else if (Unnumbered_Acknowledge_Pending || Frame_Reject_Pending)
{
continue_loop = TransmitUnnumberedFrame ();
}
else if ((data_to_transmit & PROTOCOL_USER_DATA) &&
(Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED) &&
(Data_Request_Count != 0) &&
(Outstanding_Packets < Maximum_Outstanding_Packets) &&
(Outstanding_Bytes < Maximum_Outstanding_Bytes) &&
(Peer_Receiver_Busy == FALSE))
{
continue_loop = TransmitInformationFrame ();
}
else if (Acknowledge_Pending)
{
continue_loop = TransmitSupervisoryFrame (RESPONSE_FRAME, PF_RESET);
}
else
{
continue_loop = FALSE;
}
if (continue_loop)
{
if ((T200_Active == FALSE) && (DLCI == 0))
StartTimerT203 ();
}
break;
}
}
}
/*
* BOOL CLayerQ922::TransmitUnnumberedFrame ()
*
* Functional Description
* This function builds an unnumbered packet and attempts to send it out.
* The only packets that can be sent by this function are SABME, DISC, and
* an Unnumbered Acknowledge.
*
* Formal Parameters
* None
*
* Return Value
* TRUE - If a packet was transmitted
* FALSE - If a packet was not transmitted
*
* Side Effects
* None
*
* Caveats
* None
*/
BOOL CLayerQ922::TransmitUnnumberedFrame ()
{
TRACE_OUT(("CLayerQ922::TransmitUnnumberedFrame"));
LPBYTE packet_address;
UChar command;
ULONG bytes_written;
PMemory memory;
USHORT total_length;
UChar frame_type;
/*
** Use the Supervisory Buffer to transmit the packet
*/
total_length = UNNUMBERED_HEADER_SIZE + Lower_Layer_Prepend +
Lower_Layer_Append;
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
total_length);
if (memory == NULL)
return (FALSE);
packet_address = memory -> GetPointer ();
packet_address += Lower_Layer_Prepend;
if (SABME_Pending)
{
TRACE_OUT(("Q922: DLCI %d: TransmitUnnumberedFrame: Transmitting SABME", DLCI));
command = SABME;
frame_type = COMMAND_FRAME;
}
else if (DISC_Pending)
{
TRACE_OUT(("Q922: DLCI %d: TransmitUnnumberedFrame: Transmitting DISC", DLCI));
command = DISC;
frame_type = COMMAND_FRAME;
}
else if (Unnumbered_Acknowledge_Pending)
{
TRACE_OUT(("Q922: DLCI %d: TransmitUnnumberedFrame: Transmitting UNNUMBERED_ACKNOWLEDGE", DLCI));
command = UNNUMBERED_ACKNOWLEDGE;
frame_type = RESPONSE_FRAME;
}
else if (Disconnected_Mode_Pending)
{
TRACE_OUT(("Q922: DLCI %d: TransmitUnnumberedFrame: Transmitting DISCONNECTED_MODE", DLCI));
command = DISCONNECTED_MODE;
frame_type = RESPONSE_FRAME;
}
else if (Frame_Reject_Pending)
{
TRACE_OUT(("Q922: DLCI %d: TransmitUnnumberedFrame: Transmitting FRAME_REJECT", DLCI));
command = FRAME_REJECT;
frame_type = RESPONSE_FRAME;
}
else
{
ERROR_OUT(("Q922: DLCI %d: TransmitUnnumberedFrame: Illegally called function", DLCI));
}
/*
** Assemble the packet for transmission
*/
*(packet_address + ADDRESS_BYTE_HIGH) =
(ADDRESS_HIGH(DLCI)) | frame_type | ADDRESS_MSB;
*(packet_address + ADDRESS_BYTE_LOW) = (ADDRESS_LOW(DLCI)) | ADDRESS_LSB;
*(packet_address + CONTROL_BYTE_HIGH) =
command | Unnumbered_PF_State | 0x03;
/*
** Attempt to send the packet to the lower layer
*/
m_pMultiplexer->DataRequest(DLCI, memory, (PULong) &bytes_written);
Data_Request_Memory_Manager -> FreeMemory (memory);
if (bytes_written == total_length)
{
if (SABME_Pending)
{
/*
** Start the T200 timer after the SABME has been sent
*/
StartTimerT200 ();
SABME_Pending = FALSE;
}
else if (DISC_Pending)
{
TRACE_OUT(("Q922: DLCI %d: TransmitUnnumberedPacket DISC sent", DLCI));
/*
** Start the T200 timer after the DISC has been sent
*/
DISC_Pending = FALSE;
StartTimerT200 ();
Data_Link_Mode = AWAITING_RELEASE;
}
else if (Unnumbered_Acknowledge_Pending)
{
Unnumbered_Acknowledge_Pending = FALSE;
TRACE_OUT(("Q922: DLCI %d: TransmitUnnumberedAck ack sent", DLCI));
/*
** An Unnumbered Ack packet can be sent in response to two packets,
** the SABME or DISC. If it is in response to a DISC, the
** Final_Packet flag is set to TRUE. Therefore, we need to notify
** the owner that the link is terminated.
*/
if (Final_Packet)
{
Final_Packet = FALSE;
TRACE_OUT(("Q922: DLCI %d: TransmitUnnumberedAck: Issuing Release Indication", DLCI));
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_INDICATION,
(void *) DLCI, (void *) DATALINK_NORMAL_DISCONNECT);
}
else
{
/*
** Callback to the controller to let it know that the link is
** established
*/
if ((Data_Link_Mode == TEI_ASSIGNED) ||
(Data_Link_Mode == AWAITING_ESTABLISHMENT))
{
Data_Link_Mode = MULTIPLE_FRAME_ESTABLISHED;
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_ESTABLISH_INDICATION,
(void *) DLCI);
Maximum_T200_Timeouts = Link_Maximum_T200_Timeouts;
if (DLCI == 0)
StartTimerT203 ();
}
else if ((Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED) ||
(Data_Link_Mode == TIMER_RECOVERY))
{
if (DLCI == 0)
StartTimerT203 ();
}
}
}
else if (Disconnected_Mode_Pending)
{
TRACE_OUT(("Q922: DLCI %d: TransmitUnnumberedPacket Disconnected Mode sent", DLCI));
Disconnected_Mode_Pending = FALSE;
}
else if (Frame_Reject_Pending)
{
TRACE_OUT(("Q922: DLCI %d: TransmitUnnumberedPacket Frame Reject sent", DLCI));
Frame_Reject_Pending = FALSE;
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_INDICATION,
(void *) DLCI, (void *) DATALINK_RECEIVE_SEQUENCE_EXCEPTION);
}
return (TRUE);
}
else
return (FALSE);
}
/*
* void CLayerQ922::TransmitSupervisoryFrame (
* UChar frame_type,
* UChar poll_final_bit)
*
* Functional Description
* This function builds a Supervisory frame based on the
* current state of the protocol and the passed-in parameters.
*
* Formal Parameters
* frame_type - (i) The frame type can be either COMMAND_FRAME
* or RESPONSE_FRAME
* poll_final_bit - (i) This flag is set in the packet to signal
* the remote site to respond to this packet.
*
* Return Value
* TRUE - If a packet was actually transmitted
* FALSE - If a packet was not transmitted
*
* Side Effects
* None
*
* Caveats
* None
*/
BOOL CLayerQ922::TransmitSupervisoryFrame (
UChar frame_type,
UChar poll_final_bit)
{
TRACE_OUT(("CLayerQ922::TransmitSupervisoryFrame"));
LPBYTE packet_address;
UChar command;
ULONG bytes_written;
USHORT total_length;
PMemory memory;
/*
** Transmit the packet using the Supervisory buffer
*/
total_length = DATALINK_PACKET_OVERHEAD + Lower_Layer_Prepend +
Lower_Layer_Append;
/*
** Get a memory object from the memory manager
*/
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
total_length);
if (memory == NULL)
return (FALSE);
packet_address = memory -> GetPointer ();
packet_address += Lower_Layer_Prepend;
if (Own_Receiver_Busy)
{
TRACE_OUT(("CLayerQ922::TransmitSupervisoryFrame: RECEIVER_NOT_READY"));
command = RECEIVER_NOT_READY;
}
else if (Reject_Pending)
{
TRACE_OUT(("CLayerQ922::TransmitSupervisoryFrame: REJECT"));
command = REJECT;
}
else
{
TRACE_OUT(("CLayerQ922::TransmitSupervisoryFrame: RECEIVER_READY"));
command = RECEIVER_READY;
}
/*
** Set up the header including the Receive_State_Variable which
** indicates the next packet we expect to receive.
*/
*(packet_address + ADDRESS_BYTE_HIGH) =
(ADDRESS_HIGH(DLCI)) | frame_type | ADDRESS_MSB;
*(packet_address + ADDRESS_BYTE_LOW) = (ADDRESS_LOW(DLCI)) | ADDRESS_LSB;
*(packet_address + CONTROL_BYTE_HIGH) = CONTROL_MSB | command;
*(packet_address + CONTROL_BYTE_LOW) =
(Receive_State_Variable << 1) | poll_final_bit;
/*
** Send the packet to the lower layer
*/
m_pMultiplexer->DataRequest(DLCI, memory, (PULong) &bytes_written);
Data_Request_Memory_Manager -> FreeMemory (memory);
if (bytes_written == total_length)
{
if (command == REJECT)
Reject_Pending = FALSE;
if (frame_type == COMMAND_FRAME)
{
Command_Pending = FALSE;
if (poll_final_bit == PF_SET)
{
Poll_Pending = FALSE;
/*
** If we are currently in a TIMER_RECOVERY mode, we
** need to continue to set the T200 timer to make sure
** that they receive this packet.
*/
if (Data_Link_Mode == TIMER_RECOVERY)
StartTimerT200 ();
}
}
else
{
if (poll_final_bit == PF_SET)
Final_Pending = FALSE;
}
Acknowledge_Pending = FALSE;
return (TRUE);
}
else
return (FALSE);
}
/*
* void CLayerQ922::TransmitInformationFrame (void)
*
* Functional Description
* This function builds an Information frame from its data request buffer.
* If applicable, it starts the T200 timer.
*
* Formal Parameters
* None
*
* Return Value
* TRUE - If a packet was actually transmitted
* FALSE - If a packet was not transmitted
*
* Side Effects
* None
*
* Caveats
* None
*/
BOOL CLayerQ922::TransmitInformationFrame (void)
{
TRACE_OUT(("CLayerQ922::TransmitInformationFrame"));
PMemory * data_request;
LPBYTE packet_address;
ULONG total_length;
PMemory memory;
ULONG bytes_written;
/*
** Get the address of the next memory object
*/
data_request = Data_Request + Data_Request_Tail;
memory = *data_request;
packet_address = memory -> GetPointer ();
total_length = memory -> GetLength ();
packet_address += Lower_Layer_Prepend;
/*
** Set up the packet header
*/
*(packet_address + ADDRESS_BYTE_HIGH) =
(ADDRESS_HIGH(DLCI)) | COMMAND_FRAME | ADDRESS_MSB;
*(packet_address + ADDRESS_BYTE_LOW) = (ADDRESS_LOW(DLCI)) | ADDRESS_LSB;
*(packet_address + CONTROL_BYTE_HIGH) = (Send_State_Variable << 1);
*(packet_address + CONTROL_BYTE_LOW) = (Receive_State_Variable << 1);
/*
** Send packet to lower layer
*/
m_pMultiplexer->DataRequest(DLCI, memory, (PULong) &bytes_written);
if (bytes_written == total_length)
{
if (++Data_Request_Tail == Data_Request_Total_Size)
Data_Request_Tail = 0;
Data_Request_Count--;
Outstanding_Packets++;
Outstanding_Bytes += (USHORT) total_length;
/*
** If this is the packet that the remote site is expecting,
** start the T200 timeout.
*/
if (Send_State_Variable == Acknowledge_State_Variable)
StartTimerT200 ();
Send_State_Variable = ((Send_State_Variable + 1) % SEQUENCE_MODULUS);
Acknowledge_Pending = FALSE;
return (TRUE);
}
else
return (FALSE);
}
/*
* void CLayerQ922::ProcessSABME (
* LPBYTE packet_address,
* USHORT packet_length);
*
* Functional Description
* This function decodes the SABME packet received from the remote
* site.
*
* Formal Parameters
* packet_address (i) - Address of packet
* packet_length (i) - Length of packet
*
* Return Value
* None
*
* Side Effects
* Puts us in AWAITING_ESTABLISHMENT mode
*
* Caveats
* None
*/
void CLayerQ922::ProcessSABME (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("CLayerQ922::ProcessSABME"));
BOOL command_frame;
BOOL poll_final_bit;
USHORT status;
if (packet_length != UNNUMBERED_HEADER_SIZE)
{
TRACE_OUT(("Q922: DLCI %d: SABME received: Illegal packet length = %d", DLCI, packet_length));
return;
}
status = ParseUnnumberedPacketHeader (
packet_address,
&command_frame,
&poll_final_bit);
/*
** The SABME packet can ONLY be a COMMAND, it can not be a RESPONSE
*/
if (command_frame == FALSE)
{
TRACE_OUT(("Q922: DLCI %d: SABME RESPONSE received: Illegal packet", DLCI));
return;
}
if (status == DATALINK_NO_ERROR)
{
switch (Data_Link_Mode)
{
case TEI_ASSIGNED:
case AWAITING_ESTABLISHMENT:
/*
** If we are already in this mode, remain here and respond with
** an unnumbered ack packet.
*/
Reset ();
Unnumbered_Acknowledge_Pending = TRUE;
if (poll_final_bit)
Unnumbered_PF_State = UNNUMBERED_PF_SET;
else
Unnumbered_PF_State = UNNUMBERED_PF_RESET;
break;
case MULTIPLE_FRAME_ESTABLISHED:
case TIMER_RECOVERY:
if (Send_State_Variable == Acknowledge_State_Variable)
{
TRACE_OUT(("Q922: DLCI %d: ProcessSABME: in MULTIPLE_FRAME mode: Able to recover", DLCI));
Send_State_Variable = 0;
Receive_State_Variable = 0;
Acknowledge_State_Variable = 0;
StopTimerT200 ();
Unnumbered_Acknowledge_Pending = TRUE;
if (poll_final_bit)
Unnumbered_PF_State = UNNUMBERED_PF_SET;
else
Unnumbered_PF_State = UNNUMBERED_PF_RESET;
}
else
{
TRACE_OUT(("Q922: DLCI %d: ProcessSABME: Illegal packet mode = %d", DLCI, Data_Link_Mode));
Data_Link_Mode = TEI_ASSIGNED;
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_INDICATION,
(void *) DLCI, (void *) DATALINK_ILLEGAL_PACKET_RECEIVED);
}
break;
case AWAITING_RELEASE:
Disconnected_Mode_Pending = TRUE;
if (poll_final_bit)
Unnumbered_PF_State = UNNUMBERED_PF_SET;
else
Unnumbered_PF_State = UNNUMBERED_PF_RESET;
break;
}
}
}
/*
* void CLayerQ922::ProcessUnnumberAcknowledge (
* LPBYTE packet_address,
* USHORT packet_length);
*
* Functional Description
* This function decodes an unnumbered acknowledge packet. This packet is
* received in response to a SABME or DISC packet that we sent out.
*
* Formal Parameters
* packet_address (i) - Address of packet
* packet_length (i) - Length of packet
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::ProcessUnnumberedAcknowledge (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("CLayerQ922::ProcessUnnumberedAcknowledge"));
BOOL command_frame;
BOOL poll_final_bit;
ULONG_PTR disconnect_reason;
USHORT status;
/*
** This packet MUST be the correct length or it is an error
*/
if (packet_length != UNNUMBERED_HEADER_SIZE)
{
ERROR_OUT(("Q922: DLCI %d: Unnumbered ACK received: Illegal packet length = %d", DLCI, packet_length));
return;
}
status = ParseUnnumberedPacketHeader (
packet_address,
&command_frame,
&poll_final_bit);
/*
** Unnumbered Ack packet can ONLY be a RESPONSE, it can not be a COMMAND
*/
if (command_frame)
{
ERROR_OUT(("Q922: DLCI %d: Unnumbered Ack COMMAND received: Illegal packet", DLCI));
return;
}
if (status == DATALINK_NO_ERROR)
{
switch (Data_Link_Mode)
{
case AWAITING_ESTABLISHMENT:
if (poll_final_bit)
{
/*
** If we are awaiting establishment and we receive a UA
** to our SABME, enter the MULTIPLE_FRAME_ESTABLISHED mode.
*/
Reset ();
Data_Link_Mode = MULTIPLE_FRAME_ESTABLISHED;
Maximum_T200_Timeouts = Link_Maximum_T200_Timeouts;
StopTimerT200 ();
if (DLCI == 0)
StartTimerT203 ();
/*
** Callback to the controller
*/
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_ESTABLISH_CONFIRM,
(void *) DLCI);
}
break;
case AWAITING_RELEASE:
if (Unnumbered_Acknowledge_Pending == FALSE)
{
TRACE_OUT(("Q922: DLCI %d: ProcessUnnumberedAck: Issuing Release Indication", DLCI));
if (Receive_Sequence_Exception != 0)
disconnect_reason = DATALINK_RECEIVE_SEQUENCE_EXCEPTION;
else
disconnect_reason = DATALINK_NORMAL_DISCONNECT;
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_CONFIRM,
(void *) DLCI, (void *) disconnect_reason);
}
StopTimerT200 ();
break;
case TEI_ASSIGNED:
TRACE_OUT(("Q922: DLCI %d: Illegal Unnumbered Ack", DLCI));
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_INDICATION,
(void *) DLCI, (void *) DATALINK_ILLEGAL_PACKET_RECEIVED);
break;
case MULTIPLE_FRAME_ESTABLISHED:
case TIMER_RECOVERY:
WARNING_OUT(("Q922: DLCI %d: ProcessUnnumberedAcknowledge: Illegal packet", DLCI));
break;
}
}
}
/*
* void CLayerQ922::ProcessDisconnectMode (
* LPBYTE packet_address,
* USHORT packet_length);
*
* Functional Description
* This function decodes a Disconnect Mode packet.
*
* Formal Parameters
* packet_address (i) - Address of packet
* packet_length (i) - Length of packet
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::ProcessDisconnectMode (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("CLayerQ922::ProcessDisconnectMode"));
BOOL command_frame;
BOOL poll_final_bit;
USHORT status;
if (packet_length != UNNUMBERED_HEADER_SIZE)
{
TRACE_OUT(("Q922: DLCI %d: Unnumbered ACK received: Illegal packet length = %d", DLCI, packet_length));
return;
}
status = ParseUnnumberedPacketHeader (
packet_address, &command_frame, &poll_final_bit);
/*
** DM packet can ONLY be a RESPONSE, it can not be a COMMAND
*/
if (command_frame)
{
TRACE_OUT(("Q922: DLCI %d: DM COMMAND received: Illegal packet", DLCI));
return;
}
if (status == DATALINK_NO_ERROR)
{
switch (Data_Link_Mode)
{
case AWAITING_ESTABLISHMENT:
if (poll_final_bit && Link_Originator)
{
Reset ();
Data_Link_Mode = TEI_ASSIGNED;
StopTimerT200 ();
/*
** Callback to the controller
*/
TRACE_OUT(("Q922: DLCI %d: ProcessDisconnectMode: Releasing connection", DLCI));
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_INDICATION,
(void *) DLCI, (void *) DATALINK_NORMAL_DISCONNECT);
}
break;
case AWAITING_RELEASE:
if (poll_final_bit)
{
Reset ();
Data_Link_Mode = TEI_ASSIGNED;
StopTimerT200 ();
/*
** Callback to the controller
*/
TRACE_OUT(("Q922: DLCI %d: ProcessDisconnectMode: A_R: Releasing connection", DLCI));
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_CONFIRM,
(void *) DLCI, (void *) DATALINK_NORMAL_DISCONNECT);
}
break;
case TEI_ASSIGNED:
break;
case MULTIPLE_FRAME_ESTABLISHED:
case TIMER_RECOVERY:
TRACE_OUT(("Q922: DLCI %d: ProcessDM: Illegal packet", DLCI));
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_INDICATION,
(void *) DLCI, (void *) DATALINK_ILLEGAL_PACKET_RECEIVED);
break;
}
}
}
/*
* void CLayerQ922::ProcessDISC (
* LPBYTE packet_address,
* USHORT packet_length);
*
* Functional Description
* This function decodes a DISC packet. We respond to this packet with
* an Unnumbered Ack packet.
*
* Formal Parameters
* packet_address (i) - Address of packet
* packet_length (i) - Length of packet
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::ProcessDISC (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("CLayerQ922::ProcessDISC"));
BOOL command_frame;
BOOL poll_final_bit;
USHORT status;
/*
** This packet MUST be the correct length or it is an error
*/
if (packet_length != UNNUMBERED_HEADER_SIZE)
{
TRACE_OUT(("Q922: DLCI %d: DISC received: Illegal packet length = %d", DLCI, packet_length));
return;
}
TRACE_OUT(("Q922: DLCI %d: DISCONNECT received", DLCI));
status = ParseUnnumberedPacketHeader (
packet_address, &command_frame, &poll_final_bit);
/*
** The DISC packet can ONLY be a COMMAND, it can not be a RESPONSE
*/
if (command_frame == FALSE)
{
TRACE_OUT(("Q922: DLCI %d: DISC RESPONSE received: Illegal packet", DLCI));
return;
}
if (status == DATALINK_NO_ERROR)
{
switch (Data_Link_Mode)
{
case TEI_ASSIGNED:
case AWAITING_ESTABLISHMENT:
Disconnected_Mode_Pending = TRUE;
if (poll_final_bit)
Unnumbered_PF_State = UNNUMBERED_PF_SET;
else
Unnumbered_PF_State = UNNUMBERED_PF_RESET;
break;
case AWAITING_RELEASE:
Unnumbered_Acknowledge_Pending = TRUE;
Final_Packet = TRUE;
Unnumbered_PF_State = UNNUMBERED_PF_RESET;
break;
case MULTIPLE_FRAME_ESTABLISHED:
case TIMER_RECOVERY:
Unnumbered_Acknowledge_Pending = TRUE;
Final_Packet = TRUE;
Unnumbered_PF_State = UNNUMBERED_PF_RESET;
break;
}
}
}
/*
* void CLayerQ922::ProcessFrameReject (
* LPBYTE packet_address,
* USHORT packet_length);
*
* Functional Description
* This function decodes the Frame Reject packet. We currently don't fully
* support this packet.
*
* Formal Parameters
* packet_address (i) - Address of packet
* packet_length (i) - Length of packet
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::ProcessFrameReject (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("CLayerQ922::ProcessFrameReject"));
BOOL command_frame;
BOOL poll_final_bit;
USHORT status;
/*
** This packet MUST be the correct length or it is an error
*/
if (packet_length < UNNUMBERED_HEADER_SIZE)
{
ERROR_OUT(("Q922: DLCI %d: Frame Reject received: Illegal packet length = %d", DLCI, packet_length));
return;
}
status = ParseUnnumberedPacketHeader (
packet_address, &command_frame, &poll_final_bit);
/*
** The FRMR packet can ONLY be a RESPONSE, it can not be a COMMAND
*/
if (command_frame)
{
ERROR_OUT(("Q922: DLCI %d: FRMR COMMAND received: Illegal packet", DLCI));
return;
}
if (status == DATALINK_NO_ERROR)
{
switch (Data_Link_Mode)
{
case TEI_ASSIGNED:
case AWAITING_ESTABLISHMENT:
case AWAITING_RELEASE:
case MULTIPLE_FRAME_ESTABLISHED:
case TIMER_RECOVERY:
ERROR_OUT(("Q922: DLCI %d ProcessFrameReject: Illegal packet", DLCI));
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_INDICATION,
(void *) DLCI, (void *) DATALINK_ILLEGAL_PACKET_RECEIVED);
break;
}
}
}
/*
* void CLayerQ922::ProcessReceiverReady (
* LPBYTE packet_address,
* USHORT packet_length)
*
* Functional Description
* This function decodes the Receiver Ready packet that is in the
* input buffer. From the packet, we get the packet sequence
* number that the remote site is expecting.
*
* Formal Parameters
* packet_address (i) - Address of packet
* packet_length (i) - Length of packet
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::ProcessReceiverReady (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("CLayerQ922::ProcessReceiverReady"));
BOOL command_frame;
UChar receive_sequence_number;
BOOL poll_final_bit;
USHORT status;
/*
** This packet MUST be the correct length or it is an error
*/
if (packet_length != DATALINK_PACKET_OVERHEAD)
{
ERROR_OUT(("Q922: DLCI %d: Receiver Ready received: Illegal packet length = %d", DLCI, packet_length));
return;
}
status = ParsePacketHeader (
packet_address,
packet_length,
&command_frame,
&receive_sequence_number,
&poll_final_bit);
if (status == DATALINK_NO_ERROR)
{
if (command_frame && poll_final_bit)
{
Final_Pending = TRUE;
}
Peer_Receiver_Busy = FALSE;
/*
** If the remote site is expecting a packet sequence number
** that is not equal to our Acknowledge_State_Variable,
** update it
*/
if (Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED)
{
if (Acknowledge_State_Variable != receive_sequence_number)
{
UpdateAcknowledgeState (receive_sequence_number);
/*
** If we have received the last acknowledge,
** stop the T200 timer
*/
if (Acknowledge_State_Variable == Send_State_Variable)
StopTimerT200 ();
else
StartTimerT200 ();
}
}
else
{
/*
** If we are in TIMER_RECOVERY mode, update the
** Acknowledge_State_Variable and resend the packets
** that need to be sent.
*/
UpdateAcknowledgeState (receive_sequence_number);
if ((command_frame == FALSE) && poll_final_bit)
{
ResetSendState ();
StopTimerT200 ();
if (Data_Link_Mode != AWAITING_RELEASE)
Data_Link_Mode = MULTIPLE_FRAME_ESTABLISHED;
}
}
}
else
{
ERROR_OUT(("Q922: DLCI %d: ProcessReceiverReady: Error Processing packet", DLCI));
}
}
/*
* void CLayerQ922::ProcessReceiverNotReady (
* LPBYTE packet_address,
* USHORT packet_length)
*
* Functional Description
* This function decodes the Receiver Not Ready packet that
* is in the input buffer. This packet notifies us that the
* remote site does not have room for Information packets.
* As a result of this packet, we won't send any more packets
* until the remote site sends us a Receiver Ready packet.
*
* Formal Parameters
* packet_address (i) - Address of packet
* packet_length (i) - Length of packet
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::ProcessReceiverNotReady (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("CLayerQ922::ProcessReceiverNotReady"));
BOOL command_frame;
UChar receive_sequence_number;
BOOL poll_final_bit;
USHORT status;
/*
** This packet MUST be the correct length or it is an error
*/
if (packet_length != DATALINK_PACKET_OVERHEAD)
{
TRACE_OUT(("Q922: DLCI %d: Receiver Not Ready received: Illegal packet length = %d", DLCI, packet_length));
return;
}
status = ParsePacketHeader (
packet_address,
packet_length,
&command_frame,
&receive_sequence_number,
&poll_final_bit);
if (status == DATALINK_NO_ERROR)
{
if (command_frame && poll_final_bit)
{
Final_Pending = TRUE;
}
/*
** Set the Peer_Receiver_Busy flag so that we don't send
** out any information packets.
*/
Peer_Receiver_Busy = TRUE;
UpdateAcknowledgeState (receive_sequence_number);
if (Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED)
StartTimerT200 ();
else
{
/*
** If we are in TIMER_RECOVERY state, exit TIMER_RECOVERY
** state and update the acknowledge state.
*/
if ((command_frame == FALSE) && poll_final_bit)
{
ResetSendState ();
StartTimerT200 ();
if (Data_Link_Mode != AWAITING_RELEASE)
Data_Link_Mode = MULTIPLE_FRAME_ESTABLISHED;
}
}
}
else
{
ERROR_OUT(("Q922: DLCI %d: ProcessNotReceiverReady: Error Processing packet", DLCI));
}
}
/*
* void CLayerQ922::ProcessReject (
* LPBYTE packet_address,
* USHORT packet_length)
*
* Functional Description
* This function decodes the Receiver Reject packet that
* is in the input buffer. This packet indicates that the
* remote site needs us to retransmit some packets. It sends
* the next packet sequence number that it expects.
*
* Formal Parameters
* packet_address (i) - Address of packet
* packet_length (i) - Length of packet
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::ProcessReject (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("CLayerQ922::ProcessReject"));
BOOL command_frame;
UChar receive_sequence_number;
BOOL poll_final_bit;
USHORT status;
/*
** This packet MUST be the correct length or it is an error
*/
if (packet_length != DATALINK_PACKET_OVERHEAD)
{
ERROR_OUT(("Q922: DLCI %d: REJECT received: Illegal packet length = %d", DLCI, packet_length));
return;
}
status = ParsePacketHeader (
packet_address,
packet_length,
&command_frame,
&receive_sequence_number,
&poll_final_bit);
if (status == DATALINK_NO_ERROR)
{
if (command_frame && poll_final_bit)
{
Final_Pending = TRUE;
}
Peer_Receiver_Busy = FALSE;
/*
** Update the Acknowledge_State_Variable and prepare to
** resend the packets that weren't acknowledged.
*/
UpdateAcknowledgeState (receive_sequence_number);
if (Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED)
{
ResetSendState ();
StopTimerT200 ();
}
else
{
if ((command_frame == FALSE) && poll_final_bit)
{
ResetSendState ();
StopTimerT200 ();
if (Data_Link_Mode != AWAITING_RELEASE)
Data_Link_Mode = MULTIPLE_FRAME_ESTABLISHED;
}
}
}
else
{
ERROR_OUT(("Q922: DLCI %d: ProcessReject: Error Processing packet", DLCI));
}
}
/*
* BOOL CLayerQ922::ProcessInformationFrame (
* LPBYTE packet_address,
* USHORT packet_length)
*
* Functional Description
* This function processes the information packet. It checks
* to see if it has the expected sequence number. If it does,
* it puts it into the queue which will be read by the user.
*
* Formal Parameters
* packet_address (i) - Address of packet
* packet_length (i) - Length of packet
*
* Return Value
* TRUE - If the packet was processed
* FALSE - If the packet was not processed
*
* Side Effects
* None
*
* Caveats
* None
*/
BOOL CLayerQ922::ProcessInformationFrame (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("CLayerQ922::ProcessInformationFrame"));
BOOL command_frame;
UChar receive_sequence_number;
BOOL poll_final_bit;
USHORT status;
PDataQueue read_queue;
UChar send_sequence_number;
BOOL packet_accepted;
ULONG bytes_accepted;
if (packet_length < DATALINK_PACKET_OVERHEAD)
{
ERROR_OUT(("Q922: DLCI %d: ProcessInformationFrame: Invalid packet length = %d",
DLCI, packet_length-DATALINK_PACKET_OVERHEAD));
return (FALSE);
}
if (packet_length > (DATALINK_PACKET_OVERHEAD + Maximum_Information_Size))
{
ERROR_OUT(("Q922: DLCI %d: ProcessInformationFrame: Invalid information length = %d",
DLCI, packet_length - DATALINK_PACKET_OVERHEAD));
return (FALSE);
}
/*
** If there isn't a place to put the packet, return FALSE
*/
if ((Data_Indication_Count == Data_Indication_Size) ||
Own_Receiver_Busy || (Higher_Layer == NULL))
{
return (FALSE);
}
status = ParsePacketHeader (
packet_address,
packet_length,
&command_frame,
&receive_sequence_number,
&poll_final_bit);
if (status == DATALINK_NO_ERROR)
{
if (poll_final_bit && command_frame)
{
Final_Pending = TRUE;
}
if ((Data_Link_Mode == MULTIPLE_FRAME_ESTABLISHED) &&
(Peer_Receiver_Busy == FALSE))
{
/*
** If the remote site does NOT acknowledge the last packet
** that we sent out, Update the Acknowledge State variable
** by calling UpdateAcknowledgeState()
*/
if (Acknowledge_State_Variable != receive_sequence_number)
{
UpdateAcknowledgeState (receive_sequence_number);
/*
** If the received acknowledge, reflects the last
** packet transmitted, stop the T200 timer.
*/
if (Acknowledge_State_Variable == Send_State_Variable)
StopTimerT200 ();
else
StartTimerT200 ();
}
}
else
{
/*
** If this is an I-Frame RESPONSE, exit the TIMER_RECOVERY
** state
*/
UpdateAcknowledgeState (receive_sequence_number);
if ((Data_Link_Mode == TIMER_RECOVERY) && (command_frame == FALSE)
&& poll_final_bit)
{
ResetSendState();
Data_Link_Mode = MULTIPLE_FRAME_ESTABLISHED;
StopTimerT200 ();
}
}
send_sequence_number = (*(packet_address + CONTROL_BYTE_HIGH) >> 1);
/*
** If this is the packet that we are waiting for,
** give it to the Transport Layer.
*/
if (send_sequence_number == Receive_State_Variable)
{
/*
** Try to send the packet to the higher layer,
** if it accepts it, we won't have to copy it.
*/
packet_accepted = FALSE;
if (Data_Indication_Count == 0)
{
Higher_Layer -> DataIndication (
packet_address + DATALINK_PACKET_OVERHEAD,
packet_length - DATALINK_PACKET_OVERHEAD,
&bytes_accepted);
if (bytes_accepted ==
(ULONG) (packet_length - DATALINK_PACKET_OVERHEAD))
{
packet_accepted = TRUE;
}
}
/*
** If the higher layer did not accept it, copy it into our
** Data Indication queue.
*/
if (packet_accepted == FALSE)
{
read_queue = Data_Indication + Data_Indication_Head;
memcpy ((PVoid) read_queue->buffer_address,
(PVoid) (packet_address + DATALINK_PACKET_OVERHEAD),
packet_length - DATALINK_PACKET_OVERHEAD);
read_queue->length = packet_length-DATALINK_PACKET_OVERHEAD;
if (++Data_Indication_Head == Data_Indication_Size)
Data_Indication_Head = 0;
if (++Data_Indication_Count == Data_Indication_Size)
{
Own_Receiver_Busy = TRUE;
TRACE_OUT(("Q922: DLCI %d: Own Receiver Busy", DLCI));
}
}
Receive_State_Variable =
((Receive_State_Variable + 1) % SEQUENCE_MODULUS);
Acknowledge_Pending = TRUE;
Reject_Outstanding = FALSE;
}
else
{
/*
** If we were not expecting this packet, send a REJECT
** packet to the remote site.
*/
if (Reject_Outstanding == FALSE)
{
Reject_Pending = TRUE;
Reject_Outstanding = TRUE;
}
}
}
else
{
ERROR_OUT(("Q922: DLCI %d: ProcessInformation: Error Processing packet", DLCI));
}
return (TRUE);
}
/*
* DataLinkError CLayerQ922::ParsePacketHeader (
* LPBYTE packet_address,
* USHORT packet_length,
* BOOL * command_frame,
* LPBYTE receive_sequence_number,
* BOOL * poll_final_bit)
*
* Functional Description
* This function decodes the packet header looking for three
* things:
*
* 1. Is the packet a command frame?
* 2. What is the sequence number in the packet?
* 3. Does the packet require a respones?
*
* Formal Parameters
* packet_address - (i) Address of the new packet
* packet_length - (i) Length of the new packet
* command_frame - (o) Address of variable, it is set to TRUE
* if it is a COMMAND frame and FALSE if
* it is a RESPONSE frame
* receive_sequence_number - (o) Address of variable, it holds the
* sequence number in the packet
* poll_final_bit - (o) Address of variable, it is set to TRUE
* if we need to respond to the packet and
* FALSE if we don't
*
* Return Value
* DATALINK_RECEIVE_SEQUENCE_VIOLATION -
* DATALINK_NO_ERROR -
*
* Side Effects
* None
*
* Caveats
* None
*/
DataLinkError CLayerQ922::ParsePacketHeader (
LPBYTE packet_address,
#ifdef _DEBUG
USHORT packet_length,
#else
USHORT,
#endif
BOOL * command_frame,
LPBYTE receive_sequence_number,
BOOL * poll_final_bit)
{
TRACE_OUT(("CLayerQ922::ParsePacketHeader"));
DataLinkError return_value = DATALINK_NO_ERROR;
UChar receive_sequence;
UChar send_state_sequence;
if (*(packet_address + ADDRESS_BYTE_HIGH) & COMMAND_BIT)
*command_frame = FALSE;
else
*command_frame = TRUE;
*receive_sequence_number = (*(packet_address + CONTROL_BYTE_LOW) >> 1);
if (*(packet_address + CONTROL_BYTE_LOW) & POLL_FINAL_BIT)
*poll_final_bit = TRUE;
else
*poll_final_bit = FALSE;
if (*receive_sequence_number < Acknowledge_State_Variable)
receive_sequence = *receive_sequence_number + SEQUENCE_MODULUS;
else
receive_sequence = *receive_sequence_number;
if (Send_State_Variable < Acknowledge_State_Variable)
send_state_sequence = Send_State_Variable + SEQUENCE_MODULUS;
else
send_state_sequence = Send_State_Variable;
/*
** Illegal Condition: The remote site is acknowledging a
** packet that is not in the range of transmitted packets
*/
if (receive_sequence > send_state_sequence)
{
TRACE_OUT(("Q922: DLCI %d: ParsePacketHeader: Receive Sequence Exception: length = %d", DLCI, packet_length));
TRACE_OUT(("Q922: ParsePacketHeader: receive_sequence = %d", receive_sequence));
TRACE_OUT(("Q922: ParsePacketHeader: send_state_sequence = %d", send_state_sequence));
TRACE_OUT(("Q922: ParsePacketHeader: Acknowledge_State_Var = %d", Acknowledge_State_Variable));
TRACE_OUT(("Q922: ParsePacketHeader: Send_State_Variable = %d", Send_State_Variable));
TRACE_OUT(("Q922: ParsePacketHeader: in-packet receive_sequence = %d", *receive_sequence_number));
TRACE_OUT(("Q922: ParsePacketHeader: Data_Request_Count = %d", Data_Request_Count));
/*
** The following piece of code checks the receive sequence number
** against our send state sequence number + the number of packets
** queued for transmission. We are doing this to recover from one
** of two things:
**
** 1. The T200 timeout value is not long enough.
** 2. This Q922 object is not able to check its input
** buffers quickly enough to respond to the remote site's
** command. If the machine is overloaded with work to
** process, this error can occur.
**
** We are checking to see if we are receiving an acknowledge
** for a packet that we have already transmitted once. When we
** are in this out-of-sync state, it is possible to transmit an
** information packet, timeout, and receive a supervisory packet
** that does not acknowledge the last packet. As a consequence,
** we reset our Send_State_Variable, so that we have no knowledge
** of transmitting the information packet. We then may receive
** an acknowledge for the information packet, but we don't realize
** that we ever transmitted it. This results in a Receive Sequence
** Exception.
**
** To guard against this, we are checking to see if this acknowledge
** COULD be valid. If it could be valid, we are processing it
** normally except for the receive sequence value. We are setting
** the receive_sequence_number to that last good acknowledgement and
** we will eventually re-transmit the packet. We also send up a
** warning to the node controller.
**
** If the acknowledge is not possibly in our range of packets, we
** treat it as a real Receive Sequence Exception and break the link.
*/
if (receive_sequence <= (send_state_sequence + Data_Request_Count))
{
*receive_sequence_number = Acknowledge_State_Variable;
Receive_Sequence_Recovery++;
TRACE_OUT(("Q922: ParsePacketHeader: Attempting recovery from this exception"));
TRACE_OUT(("Q922: ParsePacketHeader: Recovery = %d", Receive_Sequence_Recovery));
/*
** Let the user know that there is a problem
*/
m_pT123->OwnerCallback(m_nMsgBase + T123_STATUS_MESSAGE,
(void *) DLCI, (void *) DATALINK_TIMING_ERROR);
}
else
{
TRACE_OUT(("Q922: ParsePacketHeader: CAN NOT recover from this exception"));
Receive_Sequence_Exception++;
DISC_Pending = TRUE;
Unnumbered_PF_State = UNNUMBERED_PF_RESET;
return_value = DATALINK_RECEIVE_SEQUENCE_VIOLATION;
}
}
return (return_value);
}
/*
* DataLinkError CLayerQ922::ParseUnnumberedPacketHeader (
* BOOL * command_frame,
* LPBYTE receive_sequence_number,
* BOOL * poll_final_bit)
*
* Functional Description
* This function decodes the packet header looking for three
* things:
*
* 1. Is the packet a command frame?
* 2. What is the sequence number in the packet?
* 3. Does the packet require a respone?
*
* Formal Parameters
* command_frame - (o) Address of variable, it is set to TRUE
* if it is a COMMAND frame and FALSE if
* it is a RESPONSE frame
* receive_sequence_number - (o) Address of variable, it holds the
* sequence number in the packet
* poll_final_bit - (o) Address of variable, it is set to TRUE
* if we need to respond to the packet and
* FALSE if we don't
*
* Return Value
* DATALINK_RECEIVE_SEQUENCE_VIOLATION -
* DATALINK_NO_ERROR -
*
* Side Effects
* None
*
* Caveats
* None
*/
DataLinkError CLayerQ922::ParseUnnumberedPacketHeader (
LPBYTE packet_address,
BOOL * command_frame,
BOOL * poll_final_bit)
{
TRACE_OUT(("CLayerQ922::ParseUnnumberedPacketHeader"));
if (*(packet_address + ADDRESS_BYTE_HIGH) & COMMAND_BIT)
*command_frame = FALSE;
else
*command_frame = TRUE;
if (*(packet_address + CONTROL_BYTE_HIGH) & UNNUMBERED_PF_SET)
*poll_final_bit = TRUE;
else
*poll_final_bit = FALSE;
return (DATALINK_NO_ERROR);
}
/*
* void CLayerQ922::UpdateAcknowledgeState (
* UChar sequence_number)
*
* Functional Description
* This function updates Acknowledge_State_Variable. The parameter
* passed in is the sequence number of a packet that the remote site has
* successfully received. By receiving this sequence number, we can
* remove the packet from our write queue as well as any packet that
* was transmitted before that packet.
*
* Formal Parameters
* sequence_number - (i) Sequence number of packet successfully
* received by the remote site.
*
* Return Value
* None
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::UpdateAcknowledgeState (
UChar sequence_number)
{
TRACE_OUT(("CLayerQ922::UpdateAcknowledgeState"));
UChar packets_acknowledged;
USHORT count;
PMemory memory;
ULONG total_length;
if (Acknowledge_State_Variable != sequence_number)
{
/*
** Find the number of packets acknowledged by this sequence
** number. If the remote site receives X packets successfully,
** the next time the remote site transmits, it will send out an
** acknowledge for the LAST packet received. All packets
** received before it are acknowledged by default.
*/
if (sequence_number < Acknowledge_State_Variable)
{
packets_acknowledged = ((sequence_number + SEQUENCE_MODULUS) -
Acknowledge_State_Variable);
}
else
{
packets_acknowledged =
(sequence_number - Acknowledge_State_Variable);
}
/*
** Go thru each of the packets acknowledged and Unlock the memory
** object associated with it. This will free the memory.
*/
for (count=0; count < packets_acknowledged; count++)
{
memory = *(Data_Request + Data_Request_Acknowledge_Tail);
total_length = memory -> GetLength ();
Outstanding_Packets--;
Outstanding_Bytes -= (USHORT) total_length;
Data_Request_Memory_Manager -> UnlockMemory (memory);
if (++Data_Request_Acknowledge_Tail == Data_Request_Total_Size)
Data_Request_Acknowledge_Tail = 0;
}
Acknowledge_State_Variable = sequence_number;
}
}
/*
* void CLayerQ922::ResetSendState (void)
*
* Functional Description
* This function is called when we need to retransmit packets.
* The Send_State_Variable is reset to equal the
* Acknowledge_State_Variable.
*
* Formal Parameters
* None.
*
* Return Value
* None.
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::ResetSendState (void)
{
TRACE_OUT(("CLayerQ922::ResetSendState"));
/*
** Reset the Send_State_Variable so that we resend packets.
*/
if (Send_State_Variable != Acknowledge_State_Variable)
{
Total_Retransmitted += (DWORD) Outstanding_Packets;
TRACE_OUT(("Q922: DLCI %d: retransmitting %d packets -- Total = %ld",
DLCI, Outstanding_Packets, Total_Retransmitted));
Data_Request_Tail = Data_Request_Acknowledge_Tail;
Data_Request_Count += Outstanding_Packets;
Outstanding_Packets = 0;
Outstanding_Bytes = 0;
Send_State_Variable = Acknowledge_State_Variable;
}
}
/*
* void CLayerQ922::StartTimerT200 (void)
*
* Functional Description
* This function starts the T200 timer. This timer us started when
* we send a packet and expect a response. If the response is not
* received within the T200 time span. The timer expires and we
* enter a TIMER_RECOVERY state.
*
* Formal Parameters
* None.
*
* Return Value
* None.
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::StartTimerT200 (void)
{
TRACE_OUT(("CLayerQ922::StartTimerT200"));
if (T200_Active)
{
StopTimerT200 ();
}
if (T203_Active)
{
StopTimerT203 ();
}
T200_Handle = g_pSystemTimer->CreateTimerEvent(T200_Timeout,
TIMER_EVENT_ONE_SHOT,
this,
(PTimerFunction) &CLayerQ922::T200Timeout);
T200_Active = TRUE;
}
/*
* void CLayerQ922::StopTimerT200 (void)
*
* Functional Description
* This function stops the T200 timer. If we receive a response
* to a packet before the T200 timer expires, this function is
* called.
*
* Formal Parameters
* None.
*
* Return Value
* None.
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::StopTimerT200 (void)
{
TRACE_OUT(("CLayerQ922::StopTimerT200"));
if (T200_Active)
{
if (g_pSystemTimer->DeleteTimerEvent(T200_Handle) != TIMER_NO_ERROR)
{
TRACE_OUT(("Q922: StopTimerT200: DLCI %d: Illegal Timer handle = %d", DLCI, T200_Handle));
}
T200_Active = FALSE;
}
}
/*
* void CLayerQ922::T200Timeout (
* TimerEventHandle)
*
* Functional Description
* This function is called by the timer class when the T200
* timer expires.
*
* Formal Parameters
* None.
*
* Return Value
* None.
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::T200Timeout(TimerEventHandle)
{
TRACE_OUT(("CLayerQ922::T200Timeout"));
BOOL send_disconnect = FALSE;
T200_Active = FALSE;
N200_Count++;
TRACE_OUT(("Q922::T200Timeout: %d DLCI: Timer Recovery: N200_Count = %x", DLCI, N200_Count));
if ((Maximum_T200_Timeouts != 0xffff) &&
(N200_Count >= Maximum_T200_Timeouts))
{
Link_Stable = FALSE;
send_disconnect = TRUE;
}
switch (Data_Link_Mode)
{
case TEI_ASSIGNED:
break;
case AWAITING_ESTABLISHMENT:
if (! Link_Stable)
{
break;
}
if (Link_Originator)
{
SABME_Pending = TRUE;
Unnumbered_PF_State = UNNUMBERED_PF_SET;
}
break;
case AWAITING_RELEASE:
if (Final_Packet)
{
send_disconnect = TRUE;
}
else
{
if (! Link_Stable)
{
send_disconnect = TRUE;
}
else
{
DISC_Pending = TRUE;
Unnumbered_PF_State = UNNUMBERED_PF_SET;
}
}
break;
default:
if (! Link_Stable)
{
TRACE_OUT(("Q922: DLCI %d T200 Timeout: Broken Connection", DLCI));
Reset ();
Data_Link_Mode = TEI_ASSIGNED;
}
else
{
Data_Link_Mode = TIMER_RECOVERY;
Poll_Pending = TRUE;
StartTimerT200 ();
}
}
/*
** Notify the owner that the link is unstable
*/
if (send_disconnect)
{
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_INDICATION,
(void *) DLCI, (void *) DATALINK_REMOTE_SITE_TIMED_OUT);
}
}
/*
* void CLayerQ922::StartTimerT203 (void)
*
* Functional Description
* This function starts the T203 timer. This function is called
* when the T200 timer is not active. The T203 timer expires
* when we don't receive a packet from the remote site in T203
* seconds.
*
* Formal Parameters
* None.
*
* Return Value
* None.
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::StartTimerT203 (void)
{
TRACE_OUT(("CLayerQ922::StartTimerT203"));
if (T203_Timeout == 0)
{
return;
}
if (T203_Active)
{
StopTimerT203 ();
}
T203_Handle = g_pSystemTimer->CreateTimerEvent(
T203_Timeout, TIMER_EVENT_ONE_SHOT, this,
(PTimerFunction) &CLayerQ922::T203Timeout);
T203_Active = TRUE;
}
/*
* void CLayerQ922::StopTimerT203 (void)
*
* Functional Description
* This function stops the T203 timer. If we receive a packet
* while the T203 packet is active, this function is called.
*
* Formal Parameters
* None.
*
* Return Value
* None.
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::StopTimerT203 (void)
{
TRACE_OUT(("CLayerQ922::StopTimerT203"));
if (T203_Active)
{
g_pSystemTimer->DeleteTimerEvent(T203_Handle);
T203_Active = FALSE;
}
}
/*
* void CLayerQ922::T203Timeout (
* TimerEventHandle)
*
* Functional Description
* This function is called by the timer class when the T203
* timer expires.
*
* Formal Parameters
* None.
*
* Return Value
* None.
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerQ922::T203Timeout (TimerEventHandle)
{
TRACE_OUT(("CLayerQ922::T203Timeout"));
T203_Active = FALSE;
if (Data_Link_Mode == TEI_ASSIGNED)
{
TRACE_OUT(("Q922: DLCI %d: T203 Timeout: Releasing connection", DLCI));
m_pT123->OwnerCallback(m_nMsgBase + DATALINK_RELEASE_INDICATION,
(void *) DLCI, (void *) DATALINK_REMOTE_SITE_TIMED_OUT);
return;
}
StartTimerT200 ();
Data_Link_Mode = TIMER_RECOVERY;
Poll_Pending = TRUE;
}
/*
* ProtocolLayerError CLayerQ922::GetParameters (
* USHORT,
* USHORT * max_packet_size,
* USHORT * prepend,
* USHORT * append)
*
* Public
*
* Functional Description:
* This function returns the maximum packet size permitted by
* the higher layer.
*/
ProtocolLayerError CLayerQ922::GetParameters (
USHORT * packet_size,
USHORT * prepend,
USHORT * append)
{
TRACE_OUT(("CLayerQ922::GetParameters"));
*prepend = DATALINK_PACKET_OVERHEAD + Lower_Layer_Prepend;
*append = Lower_Layer_Append;
*packet_size = Maximum_Information_Size;
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* ProtocolLayerError CLayerQ922::RegisterHigherLayer (
* USHORT,
* PMemoryManager,
* IProtocolLayer * higher_layer);
*
* Public
*
* Functional Description:
* This function is called to register an identifier with a higher
* layer address.
*/
ProtocolLayerError CLayerQ922::RegisterHigherLayer (
ULONG_PTR,
PMemoryManager,
IProtocolLayer * higher_layer)
{
TRACE_OUT(("CLayerQ922::RegisterHigherLayer"));
Higher_Layer = higher_layer; // CLayerSCF or CLayerX224
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* ProtocolLayerError CLayerQ922::RemoveHigherLayer (
* USHORT);
*
* Public
*
* Functional Description:
* This function removes the higher layer from our list
*/
ProtocolLayerError CLayerQ922::RemoveHigherLayer (
ULONG_PTR)
{
TRACE_OUT(("CLayerQ922::RemoveHigherLayer"));
Higher_Layer = NULL;
return (PROTOCOL_LAYER_NO_ERROR);
}