windows-nt/Source/XPSP1/NT/enduser/netmeeting/t120/mst123/mplex.cpp

929 lines
27 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_T123PSTN);
/* Mplex.cpp
*
* Copyright (c) 1994-1995 by DataBeam Corporation, Lexington, KY
*
* Abstract:
* This is the implementation file for the Q922 multiplexer class. This
* class multiplexes higher layers to a single lower layer.
*
* Private Instance Variables:
* Q922_Layers - List of the higher layers we are multiplexing
* Owner_Object - Address of our owner object.
* m_pComPort - Address of our lower layer
* m_hCommLink- The identifier we pass to the lower layer. This
* is how the lower layer identifies us
* m_nMsgBase - Message base we use for owner callbacks. The
* owner identifies us by the message base
* Maximum_Packet_Size Maximum packet size we can send to lower layer
* Packet_Size - Maximum packet size the higher layer can send
* to us
* Data_Request_Buffer Buffer we use for data coming from higher layer
* Data_Request_Memory_Object Memory object used for data transmission
* Data_Request_Length Length of packet from higher layer
* Data_Request_Offset Current offset into packet. Maintains current
* position as we send to lower layer.
* Data_Indication_Buffer Buffer we use for data coming from lower layer
* Data_Indication_Length Length of packet
* Data_Indication_Ready Flag indicating that packet is ready to send up
*
* Framer - Address of packet framer object
* CRC - Address of crc generator and checker
*
* Decode_In_Progress Flag telling us if we are in the middle of a
* packet
* CRC_Size - Number of bytes in the CRC
* Disconnect - TRUE if a disconnect is pending
*
* Caveats:
* None.
*
* Authors:
* James W. Lawwill
*/
#include "mplex.h"
/*
* Multiplexer::Multiplexer (
* IObject * owner_object,
* IProtocolLayer * lower_layer,
* USHORT identifier,
* USHORT message_base,
* PPacketFrame framer,
* PCRC crc,
* BOOL * initialized)
*
* Public
*
* Functional Description:
* This function initializes the Q922 multiplexer.
*/
Multiplexer::Multiplexer
(
T123 *owner_object,
ComPort *comport, // lower layer
PhysicalHandle physical_handle,
USHORT message_base,
PPacketFrame framer,
PCRC crc,
BOOL *initialized
)
:
Q922_Layers(TRANSPORT_HASHING_BUCKETS)
{
TRACE_OUT(("Multiplexer::Multiplexer"));
USHORT overhead;
ProtocolLayerError error;
USHORT lower_layer_prepend;
USHORT lower_layer_append;
*initialized = TRUE;
m_pT123 = owner_object;
m_pComPort = comport;
m_hCommLink = physical_handle;
m_nMsgBase = message_base;
Framer = framer;
CRC = crc;
CRC_Size = 0;
m_pComPort->GetParameters(
&Maximum_Packet_Size,
&lower_layer_prepend,
&lower_layer_append);
if (Maximum_Packet_Size == 0xffff)
{
/*
** The lower layer is a stream device, base the higher maximum packet
** size on the Multiplexer max. packet size
*/
Packet_Size = MULTIPLEXER_MAXIMUM_PACKET_SIZE;
Maximum_Packet_Size = Packet_Size;
if (CRC != NULL)
{
CRC -> GetOverhead (0, &CRC_Size);
Maximum_Packet_Size += CRC_Size;
}
if (Framer != NULL)
Framer -> GetOverhead (Maximum_Packet_Size, &Maximum_Packet_Size);
}
else
{
/*
** The lower layer is a packet device, determine the max. packet
** size of the higher layer.
*/
overhead = 0;
if (Framer != NULL)
Framer -> GetOverhead (overhead, &overhead);
if (CRC != NULL)
{
CRC -> GetOverhead (0, &CRC_Size);
overhead += CRC_Size;
}
Packet_Size = Maximum_Packet_Size - overhead;
}
TRACE_OUT(("MPlex: max_packet = %d", Maximum_Packet_Size));
/*
** Now we have to allocate a buffer for data going to the lower layer
*/
if (Framer != NULL)
{
Data_Request_Buffer = (LPBYTE) LocalAlloc (LMEM_FIXED, Maximum_Packet_Size);
Data_Indication_Buffer = (LPBYTE) LocalAlloc (LMEM_FIXED, Maximum_Packet_Size);
if ((Data_Request_Buffer == NULL) ||
(Data_Indication_Buffer == NULL))
{
*initialized = FALSE;
}
}
Data_Request_Length = 0;
Data_Request_Offset = 0;
Data_Request_Memory_Object = NULL;
Data_Indication_Length = 0;
Data_Indication_Ready = FALSE;
Decode_In_Progress = FALSE;
Disconnect = FALSE;
/*
** Register with the lower layer
*/
error = m_pComPort->RegisterHigherLayer(
(ULONG_PTR) m_hCommLink,
NULL,
(IProtocolLayer *) this);
if (error != PROTOCOL_LAYER_NO_ERROR)
{
TRACE_OUT(("Multiplexer: constructor: Error registering with lower layer"));
}
}
/*
* Multiplexer::~Multiplexer (void);
*
* Public
*
* Functional Description:
* Destructor
*/
Multiplexer::~Multiplexer (void)
{
TRACE_OUT(("Multiplexer::~Multiplexer"));
PMPlexStruct lpmpStruct;
/*
** Remove our reference from the lower layer
*/
m_pComPort->RemoveHigherLayer((ULONG_PTR) m_hCommLink);
if (Framer != NULL)
{
if (Data_Request_Buffer != NULL)
LocalFree ((HLOCAL) Data_Request_Buffer);
if (Data_Indication_Buffer != NULL)
LocalFree ((HLOCAL) Data_Indication_Buffer);
}
else
{
if (Data_Request_Memory_Object != NULL)
{
if (Q922_Layers.find ((DWORD_PTR) Data_Request_DLCI, (PDWORD_PTR) &lpmpStruct))
lpmpStruct->data_request_memory_manager->UnlockMemory (Data_Request_Memory_Object);
}
}
Q922_Layers.reset();
while (Q922_Layers.iterate((PDWORD_PTR) &lpmpStruct))
delete lpmpStruct;
/*
** Delete the Framer that was instantiated by the controller.
*/
if (Framer != NULL)
delete Framer;
if (CRC != NULL)
delete CRC;
}
/*
* MultiplexerError Multiplexer::ConnectRequest (void)
*
* Public
*
* Functional Description:
* This function simply notifies the higher layer that it is ready
* for operation
*/
MultiplexerError Multiplexer::ConnectRequest (void)
{
TRACE_OUT(("Multiplexer::ConnectRequest"));
m_pT123->OwnerCallback(m_nMsgBase + NEW_CONNECTION);
return (MULTIPLEXER_NO_ERROR);
}
/*
* MultiplexerError Multiplexer::DisconnectRequest (void)
*
* Public
*
* Functional Description:
* This function removes itself from the lower layer and notifies the
* owner.
*/
MultiplexerError Multiplexer::DisconnectRequest (void)
{
TRACE_OUT(("Multiplexer::DisconnectRequest"));
if (Data_Request_Length == 0)
{
m_pT123->OwnerCallback(m_nMsgBase + BROKEN_CONNECTION);
}
Disconnect = TRUE;
return (MULTIPLEXER_NO_ERROR);
}
/*
* ProtocolLayerError Multiplexer::PollReceiver (
* ULONG)
*
* Public
*
* Functional Description:
* If this function has a packet ready to send to a higher layer, it
* attempts to send it.
*/
ProtocolLayerError Multiplexer::PollReceiver(void)
{
// TRACE_OUT(("Multiplexer::PollReceiver"));
if (Data_Indication_Ready)
{
SendDataToHigherLayer (
Data_Indication_Buffer,
Data_Indication_Length);
Data_Indication_Ready = FALSE;
}
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* ProtocolLayerError Multiplexer::PollTransmitter (
* ULONG)
*
* Public
*
* Functional Description:
* If we have data to send to the lower layer, we attempt to send it.
*/
ProtocolLayerError Multiplexer::PollTransmitter (
ULONG_PTR,
USHORT,
USHORT *,
USHORT *)
{
// TRACE_OUT(("Multiplexer::PollTransmitter"));
ULONG bytes_accepted;
HPUChar packet_address;
ProtocolLayerError return_value = PROTOCOL_LAYER_NO_ERROR;
if (Data_Request_Length != 0)
{
if (Framer != NULL)
{
m_pComPort->DataRequest(
(ULONG_PTR) m_hCommLink,
Data_Request_Buffer + Data_Request_Offset,
Data_Request_Length - Data_Request_Offset,
&bytes_accepted);
}
else
{
packet_address = (HPUChar) Data_Request_Memory_Object->GetPointer ();
m_pComPort->DataRequest(
(ULONG_PTR) m_hCommLink,
((LPBYTE) packet_address) + Data_Request_Offset,
Data_Request_Length - Data_Request_Offset,
&bytes_accepted);
}
/*
** If the lower layer has accepted all of the packet, reset
** our length and offset variables
*/
if (bytes_accepted <=
(ULONG) (Data_Request_Length - Data_Request_Offset))
{
Data_Request_Offset += (USHORT) bytes_accepted;
if (Data_Request_Offset == Data_Request_Length)
{
Data_Request_Offset = 0;
Data_Request_Length = 0;
if (Framer == NULL)
{
PMPlexStruct lpmpStruct;
/*
** Unlock the memory object so that it can be released
*/
if (Q922_Layers.find ((DWORD_PTR) Data_Request_DLCI, (PDWORD_PTR) &lpmpStruct))
lpmpStruct->data_request_memory_manager->UnlockMemory (Data_Request_Memory_Object);
Data_Request_Memory_Object = NULL;
}
/*
** If the Disconnect is pending, issue the callback
*/
if (Disconnect)
{
Disconnect = FALSE;
m_pT123->OwnerCallback(m_nMsgBase + BROKEN_CONNECTION);
}
}
}
}
return (return_value);
}
/*
* ProtocolLayerError Multiplexer::RegisterHigherLayer (
* ULONG identifier,
* PMemoryManager memory_manager,
* IProtocolLayer * q922);
*
* Public
*
* Functional Description:
* This function is called to register an identifier with a higher
* layer address.
*/
ProtocolLayerError Multiplexer::RegisterHigherLayer (
ULONG_PTR identifier,
PMemoryManager memory_manager,
IProtocolLayer * q922)
{
TRACE_OUT(("Multiplexer::RegisterHigherLayer"));
DLCI dlci;
PMPlexStruct lpmpStruct;
dlci = (DLCI) identifier;
if (Q922_Layers.find ((DWORD) dlci))
return (PROTOCOL_LAYER_REGISTRATION_ERROR);
lpmpStruct = new MPlexStruct;
if (lpmpStruct != NULL)
{
Q922_Layers.insert ((DWORD_PTR) dlci, (DWORD_PTR) lpmpStruct);
lpmpStruct -> q922 = q922;
lpmpStruct -> data_request_memory_manager = memory_manager;
}
else
{
return (PROTOCOL_LAYER_ERROR);
}
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* ProtocolLayerError Multiplexer::RemoveHigherLayer (
* ULONG identifier);
*
* Public
*
* Functional Description:
* This function removes the higher layer from our list
*/
ProtocolLayerError Multiplexer::RemoveHigherLayer (
ULONG_PTR identifier)
{
TRACE_OUT(("Multiplexer::RemoveHigherLayer"));
DLCI dlci;
PMPlexStruct lpmpStruct;
dlci = (DLCI) identifier;
if (Q922_Layers.find ((DWORD_PTR) dlci, (PDWORD_PTR) &lpmpStruct) == FALSE)
return (PROTOCOL_LAYER_REGISTRATION_ERROR);
if (Data_Request_Memory_Object != NULL)
{
if (Data_Request_DLCI == dlci)
{
/*
** Unlock the memory object so that it can be released
*/
lpmpStruct->data_request_memory_manager->UnlockMemory (Data_Request_Memory_Object);
Data_Request_Offset = 0;
Data_Request_Length = 0;
Data_Request_Memory_Object = NULL;
}
}
delete lpmpStruct;
Q922_Layers.remove ((DWORD) dlci);
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* ProtocolLayerError Multiplexer::GetParameters (
* ULONG,
* USHORT * max_packet_size,
* USHORT * prepend_bytes,
* USHORT * append_bytes)
*
* Public
*
* Functional Description:
* This function returns the maximum packet size permitted by
* the higher layer.
*/
ProtocolLayerError Multiplexer::GetParameters (
USHORT * max_packet_size,
USHORT * prepend_bytes,
USHORT * append_bytes)
{
TRACE_OUT(("Multiplexer::GetParameters"));
*max_packet_size = Packet_Size;
*prepend_bytes = 0;
*append_bytes = CRC_Size;
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* MultiplexerError Multiplexer::DataRequest (
* ULONG identifier,
* PMemory memory,
* PULong bytes_accepted)
*
* Public
*
* Functional Description:
* This function takes the packet passed in, runs it thru the framer and
* CRC, and passes it to the lower layer.
*/
ProtocolLayerError Multiplexer::DataRequest (
ULONG_PTR identifier,
PMemory memory,
PULong bytes_accepted)
{
TRACE_OUT(("Multiplexer::DataRequest"));
USHORT crc;
USHORT pending_data;
HPUChar packet_address;
ULONG length;
USHORT holding_data;
USHORT i;
DLCI dlci;
PMPlexStruct lpmpStruct;
dlci = (DLCI) identifier;
/*
** Set bytes_accepted to 0
*/
*bytes_accepted = 0;
if (Data_Request_Length != 0)
return (PROTOCOL_LAYER_NO_ERROR);
/*
** Get the address of the memory block
*/
packet_address = (HPUChar) memory -> GetPointer ();
length = memory -> GetLength ();
/*
** Remove the CRC length from the total size of the packet.
*/
length -= CRC_Size;
if (length > Packet_Size)
{
TRACE_OUT(("MPLEX: DataRequest: Packet too big"));
return (PROTOCOL_LAYER_PACKET_TOO_BIG);
}
/*
** Lock the memory object so that it won't be released
*/
if (Q922_Layers.find ((DWORD_PTR) dlci, (PDWORD_PTR) &lpmpStruct))
lpmpStruct->data_request_memory_manager->LockMemory (memory);
if (CRC != NULL)
{
/*
** Generate the CRC and put it at the end of the packet.
*/
crc = (USHORT) CRC -> CRCGenerator (
(LPBYTE) packet_address, length);
for (i=0; i<CRC_Size; i++)
*(packet_address + length + i) = (crc >> (i * 8)) & 0xff;
}
/*
** Add the CRC size to the packet length.
*/
length += CRC_Size;
if (Framer != NULL)
{
/*
** Use the framer to encode the packet
*/
Framer -> PacketEncode (
(LPBYTE) packet_address,
(USHORT) length,
Data_Request_Buffer,
Maximum_Packet_Size,
TRUE,
TRUE,
&Data_Request_Length);
/*
** If we are using a framer, we can release the memory object
** right now.
*/
lpmpStruct->data_request_memory_manager->UnlockMemory (memory);
*bytes_accepted = length;
}
else
{
/*
** Save the memory object and the identifier
*/
Data_Request_DLCI = (DLCI) dlci;
Data_Request_Memory_Object = memory;
Data_Request_Length = (USHORT) length;
*bytes_accepted = length;
}
/*
** Attempt to send the packet to the lower layer
*/
PollTransmitter (
0,
PROTOCOL_CONTROL_DATA | PROTOCOL_USER_DATA,
&pending_data,
&holding_data);
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* MultiplexerError Multiplexer::DataRequest (
* ULONG,
* LPBYTE
* ULONG
* PULong bytes_accepted)
*
* Public
*
* Functional Description:
* This function takes the packet passed in, runs it thru the framer and
* CRC, and passes it to the lower layer.
*/
ProtocolLayerError Multiplexer::DataRequest (
ULONG_PTR,
LPBYTE,
ULONG,
PULong bytes_accepted)
{
*bytes_accepted = 0;
return (PROTOCOL_LAYER_ERROR);
}
/*
* ProtocolLayerError Multiplexer::DataIndication (
* LPBYTE buffer_address,
* ULONG length,
* PULong bytes_accepted)
*
* Public
*
* Functional Description:
* This function is called by the lower layer when it has data
* ready for us.
*/
ProtocolLayerError Multiplexer::DataIndication (
LPBYTE buffer_address,
ULONG length,
PULong bytes_accepted)
{
// TRACE_OUT(("Multiplexer::DataIndication"));
BOOL process_packet = TRUE;
USHORT packet_size;
LPBYTE source_address;
USHORT source_length;
LPBYTE dest_address;
USHORT dest_length;
PacketFrameError return_value;
BOOL crc_valid;
USHORT bytes_processed;
*bytes_accepted = 0;
if (Framer == NULL)
{
*bytes_accepted = length;
/*
** If the framer does NOT exist, the data is coming to us in packet
** format
*/
if (CRC != NULL)
{
crc_valid = CRC -> CheckCRC (buffer_address, length);
if (crc_valid == FALSE)
{
TRACE_OUT(("MPLEX: Invalid CRC"));
return (PROTOCOL_LAYER_NO_ERROR);
}
length -= CRC_Size;
}
SendDataToHigherLayer (buffer_address, (USHORT) length);
}
else
{
/*
** A framer exists; the lower layer is giving us the data
** in a stream fashion
*/
Data_Indication_Ready = FALSE;
source_address = buffer_address;
source_length = (USHORT) length;
while (process_packet)
{
if (Decode_In_Progress)
{
dest_length = 0;
dest_address = NULL;
}
else
{
dest_address = Data_Indication_Buffer;
dest_length = Maximum_Packet_Size;
}
/*
** Pass the data to the framer to decode it.
*/
return_value = Framer -> PacketDecode (
source_address,
source_length,
dest_address,
dest_length,
&bytes_processed,
&packet_size,
Decode_In_Progress);
source_address = NULL;
switch (return_value)
{
case PACKET_FRAME_NO_ERROR:
/*
** A complete packet was not found by the decoder
*/
Decode_In_Progress = TRUE;
Data_Indication_Ready = FALSE;
process_packet = FALSE;
*bytes_accepted += bytes_processed;
break;
case PACKET_FRAME_PACKET_DECODED:
/*
** Complete packet found, check the CRC, and pass it to
** the higher layer.
*/
Decode_In_Progress = FALSE;
*bytes_accepted += bytes_processed;
if (CRC != NULL)
{
if (packet_size <= CRC_Size)
break;
crc_valid = CRC -> CheckCRC (
Data_Indication_Buffer,
packet_size);
if (crc_valid == FALSE)
{
TRACE_OUT(("MPLEX: Invalid CRC: packet_size = %d", packet_size));
break;
}
packet_size -= CRC_Size;
}
Data_Indication_Ready = TRUE;
Data_Indication_Length = packet_size;
/*
** Send packet on up
*/
PollReceiver();
break;
case PACKET_FRAME_DEST_BUFFER_TOO_SMALL:
/*
** The packet received is too big for our buffer.
** This sometimes occurs if a trailing flag is lost
** during transmission
*/
TRACE_OUT(("PACKET_FRAME_DEST_BUFFER_TOO_SMALL"));
Decode_In_Progress = FALSE;
*bytes_accepted += bytes_processed;
break;
case PACKET_FRAME_ILLEGAL_FLAG_FOUND:
/*
** The packet received contained an illegal flag.
*/
Decode_In_Progress = FALSE;
*bytes_accepted += bytes_processed;
break;
case PACKET_FRAME_FATAL_ERROR:
/*
** Incoming packets do not meet framer requirements.
** Tell the owner object to break the link
*/
m_pT123->OwnerCallback(m_nMsgBase + BROKEN_CONNECTION);
process_packet = FALSE;
break;
}
}
}
return (PROTOCOL_LAYER_NO_ERROR);
}
/*
* void Multiplexer::SendDataToHigherLayer (
* LPBYTE buffer_address,
* USHORT length)
*
* Functional Description
* This function is called to send a packet to the higher layer
*
* Formal Parameters
* buffer_address (i) - Buffer address
* length (i) - Number of bytes in packet
*
* Return Value
* TRUE - The packet was sent to the higher layer
* FALSE - The packet was NOT sent to the higher layer
*
* Side Effects
* None
*
* Caveats
* None
*/
void Multiplexer::SendDataToHigherLayer (
LPBYTE buffer_address,
USHORT buffer_length)
{
TRACE_OUT(("Multiplexer::SendDataToHigherLayer"));
DLCI dlci;
ProtocolLayerError error;
IProtocolLayer * q922;
ULONG bytes_accepted;
PMPlexStruct lpmpStruct;
/*
** Find out who the packet is intended for
*/
dlci = GetDLCI (buffer_address, buffer_length);
if (Q922_Layers.find((DWORD_PTR) dlci, (PDWORD_PTR) &lpmpStruct))
{
q922 = lpmpStruct->q922;
error = q922 -> DataIndication (
buffer_address,
buffer_length,
&bytes_accepted);
if (error != PROTOCOL_LAYER_NO_ERROR)
{
ERROR_OUT(("Multiplexer: SendDataToHigherLayer: Error occured on data indication to %d", dlci));
}
else
{
if (bytes_accepted != 0)
{
if (bytes_accepted != buffer_length)
{
ERROR_OUT((" Multiplexer: SendDataToHigherLayer: Error: "
"The upper layer thinks he can accept partial packets!!!"));
}
}
}
}
else
{
/*
** Packet can NOT be sent up, trash it.
*/
WARNING_OUT(("MPLEX: PollReceiver: packet received with illegal DLCI = %d", dlci));
}
return;
}
/*
* DLCI Multiplexer::GetDLCI (
* LPBYTE buffer_address,
* USHORT length)
*
* Functional Description
* This function returns the dlci of the packet.
*
* Formal Parameters
* buffer_address (i) - Buffer address
* length (i) - Number of bytes in packet
*
* Return Value
* dlci
*
* Side Effects
* None
*
* Caveats
* None
*/
DLCI Multiplexer::GetDLCI (
LPBYTE buffer_address,
USHORT buffer_size)
{
DLCI dlci;
if (buffer_size < 2)
return (ILLEGAL_DLCI);
dlci = *(buffer_address + ADDRESS_BYTE_HIGH) & 0xfc;
dlci <<= 2;
dlci |= ((*(buffer_address + ADDRESS_BYTE_LOW) & 0xf0) >> 4);
return (dlci);
}