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