#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> (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); }