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

1683 lines
54 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_T123PSTN);
/* X224.cpp
*
* Copyright (c) 1994 by DataBeam Corporation, Lexington, KY
*
* Abstract:
*
* Private Instance Variables:
* Default_PDU_Size - Default PDU size, if no arb. is done
* Data_Request_Memory_Manager - Memory manager
* Lower_Layer_Prepend - Number of bytes prepended to packet by
* lower layer
* Lower_Layer_Append - Number of bytes appended to packet byt
* lower layer
* Shutdown_Receiver - TRUE if we aren't to receive any more
* packets from the lower layer
* Shutdown_Transmitter - TRUE if we aren't to transmit any more
* packets
* Data_Request_Queue - Queue that keeps the pending user data
* requests
* Data_Indication_Queue - Queue that holds the pending user data
* indications
* Data_Indication_Memory_Pool - List that holds available data
* indication buffers.
*
* Active_Data_Indication - Address of packet structure. This
* packet holds the current data indication
* that we are reassembling
* m_pT123 - Address of owner object. Used for
* callbacks
* m_pQ922 - Address of lower layer.
* m_nMsgBase - Message base to be used for owner
* callbacks
* Maximum_PDU_Size - Max. PDU size
* Arbitrated_PDU_Size - Max. arbitrated packet size.
* Identifier - Identifier passed to lower layer to
* register ourselves.
* Data_Indication_Queue_Size - Number of data indications we will
* buffer
* Data_Indication_Reassembly_Active - Flag set if we are in the middle
* of a packet reassembly.
* State - Holds the current state of the object
* Packet_Pending - Tells which packet will be sent next.
* Reject_Cause - The reason why the error packet was sent
* Packet_Size_Respond - Set to TRUE if we are to send a TPDU
* size element in the CC packet
* Error_Buffer - Address of error buffer.
* Error_Buffer_Length - Length of error buffer.
*
* m_nLocalLogicalHandle - Local transport connection id.
* m_nRemoteLogicalHandle - Remote transport connection id.
* User_Data_Pending - Set to the size of the last packet that
* the user attempted to pass to us, that
* we couldn't accept because we ran out
* of memory.
*
* Caveats:
* None.
*
* Authors:
* James W. Lawwill
*/
#include <windowsx.h>
#include "x224.h"
/*
* CLayerX224::CLayerX224 (
* PTransportResources transport_resources,
* IObject * owner_object,
* IProtocolLayer * lower_layer,
* USHORT message_base,
* USHORT logical_handle,
* USHORT identifier,
* USHORT data_indication_queue_size,
* USHORT default_PDU_size,
* PMemoryManager dr_memory_manager,
* BOOL * initialization_success)
*
* Public
*
* Functional Description:
* This is the Transport constructor. This routine initializes all
* variables and allocates the buffers needed to operate.
*/
CLayerX224::CLayerX224
(
T123 *owner_object,
CLayerQ922 *pQ922, // lower layer
USHORT message_base,
LogicalHandle logical_handle,
ULONG identifier,
USHORT data_indication_queue_size,
USHORT default_PDU_size,
PMemoryManager dr_memory_manager,
BOOL *initialization_success
)
:
m_pT123(owner_object),
m_nMsgBase(message_base),
m_pQ922(pQ922)
{
TRACE_OUT(("CLayerX224::CLayerX224"));
ProtocolLayerError error;
m_nLocalLogicalHandle = logical_handle;
Identifier = identifier;
Default_PDU_Size = default_PDU_size;
Data_Request_Memory_Manager = dr_memory_manager;
*initialization_success = TRUE;
Shutdown_Receiver = FALSE;
Shutdown_Transmitter = FALSE;
Reject_Cause = 0;
/*
** Find the maximum packet size
*/
m_pQ922->GetParameters(
&Maximum_PDU_Size,
&Lower_Layer_Prepend,
&Lower_Layer_Append);
Arbitrated_PDU_Size = Default_PDU_Size;
/*
** Figure out what our largest PDU could be. We will use this value to
** arbitrate the maximum PDU size.
*/
Maximum_PDU_Size = (USHORT)GetMaxTPDUSize (Maximum_PDU_Size);
/*
** Register with the lower layer, so we can send and receive packets.
*/
error = m_pQ922->RegisterHigherLayer(
identifier,
Data_Request_Memory_Manager,
(IProtocolLayer *) this);
if (error != PROTOCOL_LAYER_NO_ERROR)
{
ERROR_OUT(("X224: constructor: Error registering with lower layer"));
*initialization_success = FALSE;
}
/*
** Prepare for buffer allocation
*/
Data_Indication_Queue_Size = data_indication_queue_size;
Error_Buffer = NULL;
/*
** Set member variables appropriately
*/
Active_Data_Indication = NULL;
Data_Indication_Reassembly_Active = FALSE;
Packet_Pending = TRANSPORT_NO_PACKET;
User_Data_Pending = 0;
m_nRemoteLogicalHandle = 0;
Packet_Size_Respond = FALSE;
if (*initialization_success == FALSE)
State = FAILED_TO_INITIALIZE;
else
State = NO_CONNECTION;
}
/*
* CLayerX224::~CLayerX224 (void)
*
* Public
*
* Functional Description:
* This is the Transport destructor. This routine cleans up everything.
*/
CLayerX224::~CLayerX224(void)
{
TRACE_OUT(("CLayerX224::~CLayerX224"));
PMemory lpMemory;
PTMemory lptMem;
/*
** Notify the lower layer that we are terminating
*/
m_pQ922->RemoveHigherLayer(Identifier);
/*
** Go thru the data request queue and delete the structures held in the
** queue.
*/
Data_Request_Queue.reset();
while (Data_Request_Queue.iterate ((PDWORD_PTR) &lpMemory))
{
Data_Request_Memory_Manager-> FreeMemory (lpMemory);
}
/*
** Go thru the data indication queue and delete the structures held in the
** queue.
*/
Data_Indication_Queue.reset();
while (Data_Indication_Queue.iterate ((PDWORD_PTR) &lptMem))
delete lptMem;
/*
** Go thru the data request free structure pool and delete the structures
** held in the pool.
*/
Data_Indication_Memory_Pool.reset();
while (Data_Indication_Memory_Pool.iterate ((PDWORD_PTR) &lptMem))
delete lptMem;
/*
** If there is a data indication active, delete that structure.
*/
delete Active_Data_Indication;
/*
** If the error buffer holds a packet, delete it
*/
delete [] Error_Buffer;
return;
}
/*
* TransportError CLayerX224::ConnectRequest (void)
*
* Public
*
* Functional Description:
* This function initiates a connect request.
*/
TransportError CLayerX224::ConnectRequest (void)
{
TRACE_OUT(("CLayerX224::ConnectRequest"));
if (State != NO_CONNECTION)
{
ERROR_OUT(("Transport: Illegal ConnectRequest packet"));
return (TRANSPORT_CONNECT_REQUEST_FAILED);
}
Packet_Pending = CONNECTION_REQUEST_PACKET;
return (TRANSPORT_NO_ERROR);
}
/*
* TransportError CLayerX224::ShutdownReceiver (void)
*
* Public
*
* Functional Description:
* This function stops us from receiving any more packets from the lower
* layer
*/
void CLayerX224::ShutdownReceiver (void)
{
TRACE_OUT(("CLayerX224::ShutdownReceiver"));
Shutdown_Receiver = TRUE;
}
/*
* TransportError CLayerX224::EnableReceiver (void)
*
* Public
*
* Functional Description:
* This function permits us to send packets to the user application.
*/
void CLayerX224::EnableReceiver (void)
{
TRACE_OUT(("CLayerX224::EnableReceiver"));
Shutdown_Receiver = FALSE;
}
/*
* TransportError CLayerX224::ShutdownTransmitter (void)
*
* Public
*
* Functional Description:
* This function keeps us from transmitting any more packets
*/
void CLayerX224::ShutdownTransmitter (void)
{
TRACE_OUT(("CLayerX224::ShutdownTransmitter"));
Shutdown_Transmitter = TRUE;
}
/*
* TransportError CLayerX224::PurgeRequest (void)
*
* Public
*
* Functional Description:
* This function removes all packets from out output queue that aren't
* active
*/
void CLayerX224::PurgeRequest (void)
{
TRACE_OUT(("CLayerX224::PurgeRequest"));
DWORD entries;
DWORD keep_counter = 0;
PMemory memory;
LPBYTE packet_address;
DWORD i;
if (Data_Request_Queue.isEmpty() == FALSE)
{
entries = Data_Request_Queue.entries ();
/*
** Go thru packets looking for the last PDU in the SDU
*/
Data_Request_Queue.reset();
while (Data_Request_Queue.iterate ((PDWORD_PTR) &memory))
{
keep_counter++;
packet_address = memory -> GetPointer ();
if (*(packet_address + 2) == EOT_BIT)
break;
}
TRACE_OUT(("PurgeRequest: Removing %d packets", entries-keep_counter));
for (i=keep_counter; i<entries; i++)
{
Data_Request_Memory_Manager->FreeMemory ((PMemory) Data_Request_Queue.removeLast ());
}
}
return;
}
/*
* TransportError CLayerX224::ConnectResponse (void)
*
* Public
*
* Functional Description:
* This function initiates a connect response.
*/
TransportError CLayerX224::ConnectResponse (void)
{
TRACE_OUT(("CLayerX224::ConnectResponse"));
if (State != RECEIVED_CONNECT_REQUEST_PACKET)
{
ERROR_OUT(("Transport: Illegal ConnectResponse packet"));
return (TRANSPORT_CONNECT_RESPONSE_FAILED);
}
Packet_Pending = CONNECTION_CONFIRM_PACKET;
return (TRANSPORT_NO_ERROR);
}
/*
* TransportError CLayerX224::DisconnectRequest (void)
*
* Public
*
* Functional Description:
* This function initiates a disconnect request.
*/
TransportError CLayerX224::DisconnectRequest (void)
{
TRACE_OUT(("CLayerX224::DisconnectRequest"));
if (State == SENT_CONNECT_REQUEST_PACKET)
{
/*
** The connection is being rejected, send out the DISCONNECT
** packet and wait for termination
*/
Packet_Pending = DISCONNECT_REQUEST_PACKET;
}
else
{
/*
** Normal disconnects don't send any notification to the remote site.
** It depends on the Network layer to terminate the link.
*/
m_pQ922->RemoveHigherLayer(Identifier);
m_pT123->OwnerCallback(m_nMsgBase + TPRT_DISCONNECT_INDICATION,
(void *) m_nLocalLogicalHandle);
}
return (TRANSPORT_NO_ERROR);
}
/*
* TransportError CLayerX224::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 for us.
*/
ProtocolLayerError CLayerX224::DataIndication (
LPBYTE packet_address,
ULONG packet_length,
PULong bytes_accepted)
{
TRACE_OUT(("CLayerX224::DataIndication"));
ULONG remainder_length;
USHORT class_request;
USHORT packet_type;
USHORT length;
USHORT destination_reference;
LegacyTransportData transport_data;
BOOL packet_accepted;
ULONG user_accepted;
UChar eot;
PTMemory packet;
TMemoryError packet_error;
LPBYTE temp_address;
BOOL use_default_PDU_size;
*bytes_accepted = 0;
packet_accepted = FALSE;
/*
** If the receiver is shutdown, don't accept any data
*/
if (Shutdown_Receiver)
return (PROTOCOL_LAYER_NO_ERROR);
/*
** The packet must be at least 2 bytes long
*/
if (packet_length < 2)
{
ERROR_OUT(("X224: DataIndication: Invalid packet received from lower layer: length = %d", packet_length));
return (PROTOCOL_LAYER_NO_ERROR);
}
remainder_length = packet_length;
temp_address = packet_address;
packet_address++;
packet_type = *(packet_address++) & TPDU_CODE_MASK;
remainder_length -= 2;
switch (packet_type)
{
case CONNECTION_REQUEST_PACKET:
packet_accepted = TRUE;
/*
** There should be at least 5 bytes remaining in this packet
*/
if (remainder_length < 5)
{
ERROR_OUT(("X224: DataIndication: CR: Invalid packet received from lower layer: length = %d", packet_length));
break;
}
/*
** Increment the packet address by 2 to get past the DST_REF
*/
packet_address += 2;
m_nRemoteLogicalHandle = *(packet_address++);
m_nRemoteLogicalHandle <<= 8;
m_nRemoteLogicalHandle |= *(packet_address++);
remainder_length -= 4;
/*
** Look at the class request to make sure it is 0
*/
class_request = *(packet_address++) >> 4;
remainder_length -= 1;
if (class_request != 0)
{
ERROR_OUT(("X224: DataIndication: CR packet: Illegal class request"));
ErrorPacket (
temp_address,
(USHORT) (packet_length - remainder_length));
break;
}
use_default_PDU_size = TRUE;
while (remainder_length != 0)
{
switch (*(packet_address++))
{
case TPDU_SIZE:
length = *(packet_address++);
remainder_length -= 1;
if (length != 1)
{
TRACE_OUT(("X224: DataIndication: CR packet: Illegal TPDU_Size length"));
ErrorPacket (
temp_address,
(USHORT) (packet_length - remainder_length));
break;
}
/*
** Figure out the actual PDU size
*/
Arbitrated_PDU_Size = (1 << *(packet_address++));
remainder_length -= 1;
TRACE_OUT(("X224: CR_Packet: Packet size = %d", Arbitrated_PDU_Size));
if (Arbitrated_PDU_Size > Maximum_PDU_Size)
{
Packet_Size_Respond = TRUE;
Arbitrated_PDU_Size = Maximum_PDU_Size;
}
if (AllocateBuffers() == FALSE)
{
m_pT123->OwnerCallback(m_nMsgBase + TPRT_DISCONNECT_INDICATION,
(void *) m_nLocalLogicalHandle);
}
use_default_PDU_size = FALSE;
break;
default:
ERROR_OUT(("X224: DataIndication: CR packet Unsupported parameter 0x%x", *(packet_address - 1)));
length = *(packet_address++);
remainder_length--;
packet_address += length;
remainder_length -= length;
break;
}
remainder_length--;
}
/*
** If the initiator wants to use the default PDU size, we need to
** check the default size with the Max. size to make sure it is
** valid for us.
*/
if (use_default_PDU_size)
{
if (Default_PDU_Size > Maximum_PDU_Size)
{
Packet_Size_Respond = TRUE;
Arbitrated_PDU_Size = Maximum_PDU_Size;
}
if (AllocateBuffers() == FALSE)
{
m_pT123->OwnerCallback(m_nMsgBase + TPRT_DISCONNECT_INDICATION,
(void *) m_nLocalLogicalHandle);
}
}
State = RECEIVED_CONNECT_REQUEST_PACKET;
/*
** Notify the owner that the remote site wants to start a
** connection
*/
m_pT123->OwnerCallback(m_nMsgBase + TPRT_CONNECT_INDICATION,
(void *) m_nLocalLogicalHandle);
TRACE_OUT(("X224: DataInd: ConnectRequest: max pkt = %d", Arbitrated_PDU_Size));
break;
case CONNECTION_CONFIRM_PACKET:
packet_accepted = TRUE;
/*
** There should be at least 5 bytes remaining in this packet
*/
if (remainder_length < 5)
{
ERROR_OUT(("X224: DataIndication: CC: Invalid packet received from lower layer: length = %d",
packet_length));
break;
}
destination_reference = *(packet_address++);
destination_reference <<= 8;
destination_reference |= *(packet_address++);
remainder_length -= 2;
if (destination_reference != m_nLocalLogicalHandle)
{
ERROR_OUT(("X224: DataIndication: CC packet: DST-REF incorrect"));
ErrorPacket (
temp_address,
(USHORT) (packet_length - remainder_length));
break;
}
m_nRemoteLogicalHandle = *(packet_address++);
m_nRemoteLogicalHandle <<= 8;
m_nRemoteLogicalHandle |= *(packet_address++);
class_request = *(packet_address++) >> 4;
remainder_length -= 3;
if (class_request != 0)
{
ERROR_OUT(("X224: DataIndication: CR packet: Illegal class request"));
ErrorPacket (
temp_address,
(USHORT) (packet_length - remainder_length));
break;
}
use_default_PDU_size = TRUE;
while (remainder_length != 0)
{
switch (*(packet_address++))
{
case TPDU_SIZE:
length = *(packet_address++);
remainder_length -= 1;
if (length != 1)
{
ERROR_OUT(("X224: DataIndication: CR packet: Illegal TPDU_Size length"));
ErrorPacket (
temp_address,
(USHORT) (packet_length - remainder_length));
}
Arbitrated_PDU_Size = (1 << *(packet_address++));
remainder_length -= 1;
TRACE_OUT(("X224: CC_Packet: Packet size = %d", Arbitrated_PDU_Size));
use_default_PDU_size = FALSE;
/*
** Allocate the buffers
*/
if (AllocateBuffers() == FALSE)
{
m_pT123->OwnerCallback(m_nMsgBase + TPRT_DISCONNECT_INDICATION,
(void *) m_nLocalLogicalHandle);
}
break;
default:
ERROR_OUT(("X224: DataIndication: CC packet Unsupported parameter"));
length = *(packet_address++);
remainder_length--;
packet_address += length;
remainder_length -= length;
break;
}
remainder_length--;
}
if (use_default_PDU_size)
{
if (AllocateBuffers () == FALSE)
{
m_pT123->OwnerCallback(m_nMsgBase + TPRT_DISCONNECT_INDICATION,
(void *) m_nLocalLogicalHandle);
}
}
State = CONNECTION_ACTIVE;
/*
** Notify the owner that the connect request has been confirmed
*/
m_pT123->OwnerCallback(m_nMsgBase + TPRT_CONNECT_CONFIRM,
(void *) m_nLocalLogicalHandle);
TRACE_OUT(("X224: DataInd: ConnectConfirm max pkt = %d", Arbitrated_PDU_Size));
break;
case DISCONNECT_REQUEST_PACKET:
TRACE_OUT(("X224: DataIndication: Disconnect req. received"));
/*
** Notify the owner that a disconnect has been requested. This
** message is only valid during establishment of the connection.
*/
m_pT123->OwnerCallback(m_nMsgBase + TPRT_DISCONNECT_INDICATION,
(void *) m_nLocalLogicalHandle);
packet_accepted = TRUE;
break;
case ERROR_PACKET:
TRACE_OUT(("X224: DataIndication: ERROR REQUEST received"));
/*
** Notify the owner that the remote site has detected an error in
** one of our packets.
*/
m_pT123->OwnerCallback(m_nMsgBase + TPRT_DISCONNECT_INDICATION,
(void *) m_nLocalLogicalHandle);
packet_accepted = TRUE;
break;
case DATA_PACKET:
if ((Data_Indication_Reassembly_Active == FALSE) &&
Data_Indication_Memory_Pool.isEmpty())
{
break;
}
packet_accepted = TRUE;
/*
** There should be at least 1 bytes remaining in this packet
*/
if (remainder_length < 1)
{
ERROR_OUT(("X224: DataIndication: DATA: Invalid packet "
"received from lower layer: length = %d", packet_length));
break;
}
eot = *(packet_address++);
remainder_length--;
/*
** The EOT_BIT is set if this is the last TPDU of the TSDU
*/
if ((eot & EOT_BIT) == EOT_BIT)
{
if (Data_Indication_Reassembly_Active == FALSE)
{
/*
** If the remote site has passed us an empty packet,
** just return
*/
if (remainder_length == 0)
break;
/*
** If this is a single packet and there aren't any
** other packets preceeding it, try to send it to the
** user without copying it into our own buffers
*/
if (Data_Indication_Queue.isEmpty())
{
transport_data.logical_handle = m_nLocalLogicalHandle;
transport_data.pbData = packet_address;
transport_data.cbDataSize = remainder_length;
/*
** Issue the user callback to give the user the data.
*/
user_accepted = ::NotifyT120(TRANSPORT_DATA_INDICATION, &transport_data);
/*
** If the user appliction does NOT accept the packet
** shutdown the receiver and wait for the user
** to re-enable it.
*/
if (user_accepted == TRANSPORT_NO_ERROR)
break;
else
Shutdown_Receiver = TRUE;
}
/*
** Put the packet into the DataIndication queue
*/
packet = (PTMemory) Data_Indication_Memory_Pool.get ();
packet_error = packet->Append (packet_address, remainder_length);
switch (packet_error)
{
case TMEMORY_NO_ERROR:
Data_Indication_Queue.append ((DWORD_PTR) packet);
break;
case TMEMORY_NONFATAL_ERROR:
case TMEMORY_FATAL_ERROR:
packet_accepted = FALSE;
break;
}
}
else
{
/*
** Add this PDU to the currently active SDU
*/
packet_error = Active_Data_Indication -> Append (
packet_address,
remainder_length);
switch (packet_error)
{
case TMEMORY_NO_ERROR:
Data_Indication_Reassembly_Active = FALSE;
Data_Indication_Queue.append ((DWORD_PTR) Active_Data_Indication);
Active_Data_Indication = NULL;
/*
** Call PollReceiver (), it will attempt to pass
** the packet on up to the user.
*/
PollReceiver();
break;
case TMEMORY_NONFATAL_ERROR:
case TMEMORY_FATAL_ERROR:
packet_accepted = FALSE;
break;
}
}
}
else
{
/*
** If the remote site is passing us a zero-length packet,
** just return
*/
if (remainder_length == 0)
break;
/*
** This is NOT the last packet in the incoming SDU, copy it
** into the data indication buffer and wait for the next packet
*/
if (Data_Indication_Reassembly_Active == FALSE)
{
Data_Indication_Reassembly_Active = TRUE;
Active_Data_Indication = (PTMemory) Data_Indication_Memory_Pool.get ();
}
packet_error = Active_Data_Indication -> Append (
packet_address,
remainder_length);
switch (packet_error)
{
case TMEMORY_NO_ERROR:
break;
case TMEMORY_NONFATAL_ERROR:
case TMEMORY_FATAL_ERROR:
packet_accepted = FALSE;
break;
}
}
break;
default:
ERROR_OUT(("X224: Illegal packet"));
break;
}
if (packet_accepted)
*bytes_accepted = packet_length;
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* ProtocolLayerError CLayerX224::PollTransmitter (
* ULONG,
* USHORT,
* USHORT * pending_data,
* USHORT *)
*
* Public
*
* Functional Description:
* This function is called periodically to give X224 a chance to transmit
* data.
*/
ProtocolLayerError CLayerX224::PollTransmitter (
ULONG_PTR,
USHORT,
USHORT * pending_data,
USHORT *)
{
// TRACE_OUT(("CLayerX224::PollTransmitter"));
LPBYTE packet_address;
ULONG bytes_accepted;
USHORT counter;
USHORT packet_size;
ULONG total_length;
USHORT packet_length;
PMemory memory;
BOOL continue_loop = TRUE;
while (continue_loop)
{
switch (Packet_Pending)
{
case CONNECTION_REQUEST_PACKET:
/*
** Add up the packet length, don't forget the 1 byte
** for the Length Indicator
*/
total_length =
CONNECT_REQUEST_HEADER_SIZE +
TPDU_ARBITRATION_PACKET_SIZE +
1 +
Lower_Layer_Prepend +
Lower_Layer_Append;
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
total_length);
if (memory == NULL)
{
continue_loop = FALSE;
break;
}
packet_address = memory -> GetPointer ();
packet_address += Lower_Layer_Prepend;
*(packet_address++) =
CONNECT_REQUEST_HEADER_SIZE +
TPDU_ARBITRATION_PACKET_SIZE;
*(packet_address++) = CONNECTION_REQUEST_PACKET;
/*
** The following 2 bytes are the destination reference
*/
*(packet_address++) = 0;
*(packet_address++) = 0;
*(packet_address++) = (BYTE)(m_nLocalLogicalHandle >> 8);
*(packet_address++) = (BYTE)(m_nLocalLogicalHandle & 0xff);
/*
** The following byte is the Class/Options
*/
*(packet_address++) = 0;
/*
** Add TPDU arbitration data
*/
*(packet_address++) = TPDU_SIZE;
*(packet_address++) = 1;
/*
** Code our maximum PDU size into the X224 scheme
*/
Arbitrated_PDU_Size = Maximum_PDU_Size;
packet_size = Arbitrated_PDU_Size;
counter = 0;
while (packet_size > 1)
{
packet_size >>= 1;
counter++;
}
*(packet_address++) = (unsigned char) counter;
/*
** Attempt to send the packet to the lower layer
*/
m_pQ922->DataRequest(Identifier, memory, &bytes_accepted);
/*
** We assume that the lower layer has a packet input
** interface, if it does not, there has been a major error.
*/
if (bytes_accepted == total_length)
{
Packet_Pending = TRANSPORT_NO_PACKET;
State = SENT_CONNECT_REQUEST_PACKET;
}
else
continue_loop = FALSE;
Data_Request_Memory_Manager -> FreeMemory (memory);
break;
case CONNECTION_CONFIRM_PACKET:
packet_length = CONNECT_CONFIRM_HEADER_SIZE;
if (Packet_Size_Respond)
packet_length += TPDU_ARBITRATION_PACKET_SIZE;
total_length = packet_length +
1 +
Lower_Layer_Prepend +
Lower_Layer_Append;
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
total_length);
if (memory == NULL)
{
continue_loop = FALSE;
break;
}
packet_address = memory -> GetPointer ();
packet_address += Lower_Layer_Prepend;
/*
** Build the packet
*/
*(packet_address++) = (UChar) packet_length;
*(packet_address++) = CONNECTION_CONFIRM_PACKET;
*(packet_address++) = (BYTE)(m_nRemoteLogicalHandle >> 8);
*(packet_address++) = (BYTE)(m_nRemoteLogicalHandle & 0xff);
*(packet_address++) = (BYTE)(m_nLocalLogicalHandle >> 8);
*(packet_address++) = (BYTE)(m_nLocalLogicalHandle & 0xff);
/*
** Set the Class/Options to 0
*/
*(packet_address++) = 0;
/*
** Packet_Size_Respond is TRUE if we are suppose to respond
** to the TPDU element in the Connect Request packet
*/
if (Packet_Size_Respond)
{
/*
** Add TPDU arbitration data
*/
*(packet_address++) = TPDU_SIZE;
*(packet_address++) = 1;
packet_size = Arbitrated_PDU_Size;
counter = 0;
while (packet_size > 1)
{
packet_size >>= 1;
counter++;
}
*(packet_address++) = (unsigned char) counter;
}
/*
** Attempt to send the packet to the lower layer
*/
m_pQ922->DataRequest(Identifier, memory, &bytes_accepted);
if (bytes_accepted == total_length)
{
Packet_Pending = TRANSPORT_NO_PACKET;
State = CONNECTION_ACTIVE;
}
else
continue_loop = FALSE;
Data_Request_Memory_Manager -> FreeMemory (memory);
break;
case DISCONNECT_REQUEST_PACKET:
/*
** Add 1 to the length for the Length Indicator
*/
total_length = DISCONNECT_REQUEST_HEADER_SIZE +
1 +
Lower_Layer_Prepend +
Lower_Layer_Append;
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
total_length);
if (memory == NULL)
{
continue_loop = FALSE;
break;
}
packet_address = memory -> GetPointer ();
packet_address += Lower_Layer_Prepend;
TRACE_OUT(("X224: Sending Disconnect Request Packet"));
*(packet_address++) = DISCONNECT_REQUEST_HEADER_SIZE;
*(packet_address++) = DISCONNECT_REQUEST_PACKET;
*(packet_address++) = (BYTE)(m_nRemoteLogicalHandle >> 8);
*(packet_address++) = (BYTE)(m_nRemoteLogicalHandle & 0xff);
/*
** Set the source reference to 0, this packet will only
** be sent as a refusal to a Connect Request, therefore
** this value should be 0
*/
*(packet_address++) = 0;
*(packet_address++) = 0;
*(packet_address++) = DISCONNECT_REASON_NOT_SPECIFIED;
/*
** Attempt to send packet to lower layer
*/
m_pQ922->DataRequest(Identifier, memory, &bytes_accepted);
if (bytes_accepted == total_length)
{
Packet_Pending = TRANSPORT_NO_PACKET;
State = SENT_DISCONNECT_REQUEST_PACKET;
}
continue_loop = FALSE;
Data_Request_Memory_Manager -> FreeMemory (memory);
break;
case ERROR_PACKET:
TRACE_OUT(("X224: Sending Error Packet"));
total_length = ERROR_HEADER_SIZE +
Error_Buffer_Length +
1 +
2 +
Lower_Layer_Prepend +
Lower_Layer_Append;
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
total_length);
if (memory == NULL)
{
continue_loop = FALSE;
break;
}
packet_address = memory -> GetPointer ();
packet_address += Lower_Layer_Prepend;
*(packet_address++) =
ERROR_HEADER_SIZE + Error_Buffer_Length;
*(packet_address++) = ERROR_PACKET;
*(packet_address++) = (BYTE)(m_nRemoteLogicalHandle >> 8);
*(packet_address++) = (BYTE)(m_nRemoteLogicalHandle & 0xff);
*(packet_address++) = Reject_Cause;
*(packet_address++) = INVALID_TPDU;
*(packet_address++) = (UChar) Error_Buffer_Length;
memcpy (packet_address, Error_Buffer, Error_Buffer_Length);
/*
** Attempt to send packet to lower layer
*/
m_pQ922->DataRequest(Identifier, memory, &bytes_accepted);
if (bytes_accepted == total_length)
{
delete [] Error_Buffer;
Error_Buffer = NULL;
Packet_Pending = TRANSPORT_NO_PACKET;
State = SENT_CONNECT_REQUEST_PACKET;
}
else
continue_loop = FALSE;
Data_Request_Memory_Manager -> FreeMemory (memory);
break;
case TRANSPORT_NO_PACKET:
if (Data_Request_Queue.isEmpty() == FALSE)
{
/*
** Get the next packet from the queue
*/
memory = (PMemory) Data_Request_Queue.read ();
total_length = memory -> GetLength ();
m_pQ922->DataRequest(Identifier, memory, &bytes_accepted);
if (bytes_accepted == total_length)
{
Data_Request_Queue.get ();
Data_Request_Memory_Manager -> FreeMemory (memory);
}
else
continue_loop = FALSE;
}
else
continue_loop = FALSE;
break;
}
}
if (Data_Request_Queue.isEmpty())
*pending_data = 0;
else
*pending_data = PROTOCOL_USER_DATA;
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* TransportError CLayerX224::DataRequest (
* ULONG,
* LPBYTE packet_address,
* USHORT packet_length,
* USHORT * bytes_accepted)
*
* Public
*
* Functional Description:
* This function takes a packet from the user and queues it for
* transmission.
*/
ProtocolLayerError CLayerX224::DataRequest (
ULONG_PTR,
LPBYTE packet_address,
ULONG packet_length,
PULong bytes_accepted)
{
TRACE_OUT(("CLayerX224::DataRequest"));
ULONG total_packet_size;
ULONG packet_size;
DataRequestQueue temporary_queue;
PMemory memory;
BOOL packet_failed = FALSE;
LPBYTE address;
*bytes_accepted = 0;
if (Shutdown_Transmitter)
return (PROTOCOL_LAYER_NO_ERROR);
total_packet_size = packet_length;
/*
** Create enough PDUs to hold the packet. We don't actually copy the
** packet into the new buffers until we know that we can get enough
** space.
*/
while (total_packet_size != 0)
{
if (total_packet_size >
(ULONG) (Arbitrated_PDU_Size - DATA_PACKET_HEADER_SIZE))
{
packet_size = Arbitrated_PDU_Size - DATA_PACKET_HEADER_SIZE;
}
else
packet_size = total_packet_size;
total_packet_size -= packet_size;
memory = Data_Request_Memory_Manager -> AllocateMemory (
NULL,
packet_size +
DATA_PACKET_HEADER_SIZE +
Lower_Layer_Prepend +
Lower_Layer_Append);
if (memory == NULL)
{
packet_failed = TRUE;
break;
}
temporary_queue.append ((DWORD_PTR) memory);
}
/*
** If we were unable to allocate memory for the packet, release the memory
** that we did allocate.
*/
if (packet_failed)
{
temporary_queue.reset();
while (temporary_queue.iterate ((PDWORD_PTR) &memory))
{
Data_Request_Memory_Manager->FreeMemory (memory);
}
/*
** Set the User_Data_Pending flag to the packet_length so we can
** notify the user when buffer space is available.
*/
User_Data_Pending = packet_length;
}
else
{
User_Data_Pending = 0;
total_packet_size = packet_length;
/*
** Go thru each of the PDUs and actually create them.
*/
temporary_queue.reset();
while (temporary_queue.iterate ((PDWORD_PTR) &memory))
{
if (total_packet_size >
(ULONG) (Arbitrated_PDU_Size - DATA_PACKET_HEADER_SIZE))
{
packet_size = Arbitrated_PDU_Size - DATA_PACKET_HEADER_SIZE;
}
else
packet_size = total_packet_size;
address = memory -> GetPointer ();
memcpy (
address + DATA_PACKET_HEADER_SIZE + Lower_Layer_Prepend,
packet_address + (USHORT) (packet_length - total_packet_size),
packet_size);
total_packet_size -= packet_size;
/*
** This is the header for a data packet
*/
address += Lower_Layer_Prepend;
*address = 2;
*(address + 1) = DATA_PACKET;
if (total_packet_size == 0)
*(address + 2) = EOT_BIT;
else
*(address + 2) = 0;
/*
** Load the memory object into the queue
*/
Data_Request_Queue.append ((DWORD_PTR) memory);
}
*bytes_accepted = packet_length;
}
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* ProtocolLayerError CLayerX224::DataRequest (
* ULONG,
* PMemory,
* USHORT * bytes_accepted)
*
* Public
*
* Functional Description:
* This function takes a packet from the user and queues it for
* transmission.
*/
ProtocolLayerError CLayerX224::DataRequest (
ULONG_PTR,
PMemory,
PULong bytes_accepted)
{
*bytes_accepted = 0;
return (PROTOCOL_LAYER_ERROR);
}
/*
* ProtocolLayerError CLayerX224::PollReceiver (
* ULONG)
*
* Public
*
* Functional Description:
* This function should be called periodically to allow us to send received
* packets to the user.
*/
ProtocolLayerError CLayerX224::PollReceiver(void)
{
// TRACE_OUT(("CLayerX224::PollReceiver"));
LegacyTransportData transport_data;
ULONG packet_accepted;
PTMemory packet;
HPUChar packet_address;
ULONG packet_length;
if (Shutdown_Receiver)
return (PROTOCOL_LAYER_NO_ERROR);
/*
** If I have any packets in my receive buffers that
** need to go to higher layers, do it now
*/
while (Data_Indication_Queue.isEmpty () == FALSE)
{
packet = (PTMemory) Data_Indication_Queue.read ();
packet -> GetMemory (
&packet_address,
&packet_length);
transport_data.logical_handle = m_nLocalLogicalHandle;
transport_data.pbData = (LPBYTE) packet_address;
transport_data.cbDataSize = packet_length;
packet_accepted = ::NotifyT120(TRANSPORT_DATA_INDICATION, &transport_data);
/*
** If the user returns anything but TRANSPORT_NO_ERROR, it could not
** accept the packet. We will try to send the packet again later.
*/
if (packet_accepted == TRANSPORT_NO_ERROR)
{
Data_Indication_Queue.get ();
packet -> Reset ();
Data_Indication_Memory_Pool.append ((DWORD_PTR) packet);
}
else
{
/*
** If the user appliction does NOT accept the packet
** shutdown the receiver and wait for the user to re-enable it.
*/
Shutdown_Receiver = TRUE;
break;
}
}
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* ProtocolLayerError CLayerX224::GetParameters (
* ULONG,
* USHORT * packet_size)
*
* Public
*
* Functional Description:
* This function returns the maximum allowable TSDU.
*/
ProtocolLayerError CLayerX224::GetParameters (
USHORT *,
USHORT *,
USHORT *)
{
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* ProtocolLayerError CLayerX224::RegisterHigherLayer (
* ULONG,
* PMemoryManager,
* IProtocolLayer *)
*
* Public
*
* Functional Description:
* This function does nothing. The only reason it is here is because this
* class inherits from ProtocolLayer and this function is pure virtual in
* that class.
*/
ProtocolLayerError CLayerX224::RegisterHigherLayer (
ULONG_PTR,
PMemoryManager,
IProtocolLayer *)
{
return (PROTOCOL_LAYER_REGISTRATION_ERROR);
}
/*
* ProtocolLayerError CLayerX224::RemoveHigherLayer (
* ULONG)
*
* Public
*
* Functional Description:
* This function does nothing. The only reason it is here is because this
* class inherits from ProtocolLayer and this function is pure virtual in
* that class.
*/
ProtocolLayerError CLayerX224::RemoveHigherLayer (
ULONG_PTR)
{
return (PROTOCOL_LAYER_REGISTRATION_ERROR);
}
/*
* BOOL CLayerX224::AllocateBuffers ()
*
* Functional Description
* This function allocates the data request and data indication buffers.
* and sets up the memory pools necessary. It also sets up the Control
* buffer for control packets.
*
* Formal Parameters
* None
*
* Return Value
* None.
*
* Side Effects
* None
*
* Caveats
* None
*/
BOOL CLayerX224::AllocateBuffers ()
{
TRACE_OUT(("CLayerX224::AllocateBuffers"));
PTMemory packet;
USHORT i;
ULONG total_packet_size;
TMemoryError error;
total_packet_size = MAXIMUM_USER_DATA_SIZE;
for (i=0; i<Data_Indication_Queue_Size; i++)
{
DBG_SAVE_FILE_LINE
packet = new TMemory (
total_packet_size,
0,
&error);
if (error == TMEMORY_NO_ERROR)
Data_Indication_Memory_Pool.append ((DWORD_PTR) packet);
else
return (FALSE);
}
return (TRUE);
}
/*
* void CLayerX224::ErrorPacket (
* LPBYTE packet_address,
* USHORT packet_length)
*
* Functional Description
* This function stores the packet into our own error buffer and prepares
* to send it out
*
* Formal Parameters
* None
*
* Return Value
* None.
*
* Side Effects
* None
*
* Caveats
* None
*/
void CLayerX224::ErrorPacket (
LPBYTE packet_address,
USHORT packet_length)
{
TRACE_OUT(("CLayerX224::ErrorPacket"));
DBG_SAVE_FILE_LINE
Error_Buffer = new BYTE[packet_length];
if (NULL != Error_Buffer)
{
Error_Buffer_Length = packet_length;
memcpy (Error_Buffer, packet_address, packet_length);
Packet_Pending = ERROR_PACKET;
}
}
/*
* void CLayerX224::CheckUserBuffers ()
*
* Public
*
* Functional Description:
* This function issues TRANSPORT_BUFFER_AVAILABLE_INDICATIONs to the
* user if available.
*/
void CLayerX224::CheckUserBuffers ()
{
// TRACE_OUT(("CLayerX224::CheckUserBuffers"));
ULONG user_data_size;
ULONG buffer_size;
ULONG full_size_buffers_needed;
ULONG full_size_buffer_count;
ULONG partial_buffer_size;
ULONG partial_buffer_count;
if (User_Data_Pending == 0)
return;
/*
** Determine the user data size in a packet, then determine
** how many buffers will be needed to accept that packet.
*/
user_data_size = Arbitrated_PDU_Size - DATA_PACKET_HEADER_SIZE;
full_size_buffers_needed = User_Data_Pending / user_data_size;
/*
** Find out how many full size buffers are available
*/
if (full_size_buffers_needed != 0)
{
/*
** Increment full_size_buffers_needed to account for our priority
** value.
*/
buffer_size =
Arbitrated_PDU_Size + Lower_Layer_Prepend + Lower_Layer_Append;
full_size_buffer_count = Data_Request_Memory_Manager ->
GetBufferCount (buffer_size);
if (full_size_buffer_count < full_size_buffers_needed)
return;
}
partial_buffer_size = User_Data_Pending % user_data_size;
if (partial_buffer_size != 0)
{
if ((full_size_buffers_needed == 0) ||
(full_size_buffer_count == full_size_buffers_needed))
{
buffer_size = partial_buffer_size +
DATA_PACKET_HEADER_SIZE +
Lower_Layer_Prepend +
Lower_Layer_Append;
partial_buffer_count = Data_Request_Memory_Manager ->
GetBufferCount (buffer_size);
if (full_size_buffers_needed == 0)
{
if (partial_buffer_count == 0)
return;
}
else
{
if ((partial_buffer_count == full_size_buffer_count) ||
(partial_buffer_count == 0))
{
return;
}
}
}
}
User_Data_Pending = 0;
::NotifyT120(TRANSPORT_BUFFER_EMPTY_INDICATION, (void *) m_nLocalLogicalHandle);
return;
}
/*
* static ULONG CLayerX224::GetMaxTPDUSize (
* ULONG max_lower_layer_pdu)
*
* Public
*
* Functional Description:
* This function accepts a value for the lower layer max. PDU size
* and returns the max. PDU size that this Transport can support
* based on it. X224 only suports max PDU sizes of 128, 256, 512,
* 1024, and 2048. So, if the max_lower_layer_pdu is 260, the
* Transport can only have a max pdu size of 256.
*/
ULONG CLayerX224::GetMaxTPDUSize (
ULONG max_lower_layer_pdu)
{
TRACE_OUT(("CLayerX224::GetMaxTPDUSize"));
ULONG max_tpdu_size;
if (max_lower_layer_pdu < 256)
max_tpdu_size = 128;
else if (max_lower_layer_pdu < 512)
max_tpdu_size = 256;
else if (max_lower_layer_pdu < 1024)
max_tpdu_size = 512;
else if (max_lower_layer_pdu < 2048)
max_tpdu_size = 1024;
else
max_tpdu_size = 2048;
return (max_tpdu_size);
}