?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE NETWORK ACCESS: Transport Access Agent' ??
MODULE nlm$transport_access_agent;

{ PURPOSE:
{   This module contains the procedures necessary to communicate with an OSI transport layer
{   that exists in a connected communications device.  This module contains the complete
{   transport access agent (TAA) with the exception of nlp$ta_send_data which is an inline
{   procedure.
{
{ DESIGN:
{   The transport access agent is an interface to the osi transport layer which
{   resides in a connected communications device.  Requests can be sent from the TAA
{   to the device and the device in turn can send requests (indications) to the TAA.
{
{   The main function of the transport access agent (TAA) is to send data to a
{   communication device and receive data from the communication device.  To establish
{   communications with the communications device the first step is to issue a connect
{   request or wait to receive a connect indication from the device.  After the connect
{   request has been received the receiver (the peer) can accept the connection with a
{   connect confirm.  Once the connect confirm has been issued or received the
{   the communication path (connection) is open and ready to process data requests and
{   data indications.
{
{   There are two types of data: normal data (data) and expedited data.
{   Data is subject to flow control whereas expedited data is not.  Although,
{   an expedited data request may be rejected if the current number of outstanding
{   expedited data requests equals the maximum unconfirmed expedited data requests.
{
{   The communication path is broken when the user issues a disconnect request
{   or a disconnect indication is received.
{
{ NOTES:
{   If the transport access agent detects an error on any request or any indication
{   it will release all data associated with the erroneous request or indication.
{   The procedures are in a modified alphabetical order.  The first two procedures
{   are the event processors.  The following procedures are in alphabetical order.
{   The design document for this module is A7947.

?? NEWTITLE := 'Finite State Machine Requests', EJECT ??
{
{ \--------------+------------------+------------------+------------------+------------------+---------------+
{  ----\   STATE | nlc$ta_closed    | nlc$ta_connect_  | nlc$ta_connect_  | nlc$ta_open &    | nlc$ta_open & |
{        ----\   |                  | confirm_wait     | response_wait    |  count < max     |  count = max  |
{  REQUEST   ----|        (1)       |        (2)       |        (3)       |    *   (4) **    |    * (4) **   |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ nlp$ta_        |      (1)->(2)*** |                  |                  |                  |               |
{ request_       |                  |         -        |         -        |         -        |         -     |
{ connection     |                  |                  |                  |                  |               |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ nlp$ta_        | NAE$TA_          | NAE$TA_ACCEPT_   |      (3)->(4)    | NAE$TA_ACCEPT_   | NAE$TA_ACCEPT_|
{ accept_        | CONNECTION_      | CONN_NOT_        |                  | CONN_NOT_        | CONN_NOT_     |
{ connection     | TERMINATED ****  | PENDING          |                  | PENDING          | PENDING       |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ nlp$ta_        | NAE$TA_          |      (2)->(1)    |      (3)->(1)    |      (4)->(1)    |      (4)->(1) |
{ disconnect     | CONNECTION_      |                  |                  |                  |               |
{ connection     | TERMINATED       |                  |                  |                  |               |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ nlp$ta_        | NAE$TA_          | NAE$TA_          | NAE$TA_          |      (4)->(4)    |      (4)->(4) |
{ send_data      | CONNECTION_      | CONNECTION_NOT_  | CONNECTION_NOT_  |                  |               |
{                | TERMINATED       | ESTABLISHED      | ESTABLISHED      |                  |               |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ nlp$ta_        | NAE$TA_          | NAE$TA_          | NAE$TA_          |                  | NAE$TA_       |
{ send_          | CONNECTION_      | CONNECTION_NOT_  | CONNECTION_NOT_  | count = count + 1| EXPEDITED_    |
{ expedited_     | TERMINATED       | ESTABLISHED      | ESTABLISHED      |   *       *      | REQUEST_LIMIT |
{ data           |                  |                  |                  |                  |               |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
?? OLDTITLE ??
?? NEWTITLE := 'Finite State Machine Indications', EJECT ??
{ \--------------+------------------+------------------+------------------+------------------+---------------+
{  ----\ STATE   | nlc$ta_closed    | nlc$ta_connect_  | nlc$ta_connect_  | nlc$ta_open      | nlc$ta_open   |
{      ----\     |                  | confirm_wait     | response_wait    | count = 0        | count > 0     |
{  INDICATION----|        (1)       |        (2)       |        (3)       |        (4)       |       (4)     |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ connect_       |      (1)->(3)    | PROTOCOL_ERROR   | PROTOCOL_ERROR   | PROTOCOL_ERROR   | PROTOCOL_ERROR|
{ indication     |                  |     *****        |                  |                  |               |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ connect_       | PROTOCOL_ERROR   |      (2)->(4)    | PROTOCOL_ERROR   | PROTOCOL_ERROR   | PROTOCOL_ERROR|
{ confirm        |                  |                  |                  |                  |               |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ disconnect_    | PROTOCOL_ERROR   |      (2)->(1)    |      (3)->(1)    |      (4)->(1)    |      (4)->(1) |
{ indication     |                  |                  |                  |                  |               |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ data_          | PROTOCOL_ERROR   | PROTOCOL_ERROR   | PROTOCOL_ERROR   |      (4)->(4)    |      (4)->(4) |
{ indication     |                  |                  |                  |                  |               |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ expedited_data | PROTOCOL_ERROR   | PROTOCOL_ERROR   | PROTOCOL_ERROR   |      (4)->(4)    |      (4)->(4) |
{ indication     |                  |                  |                  |                  |               |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ expedited_data | PROTOCOL_ERROR   | PROTOCOL_ERROR   | PROTOCOL_ERROR   | PROTOCOL_ERROR   | count=count-1 |
{ confirm        |                  |                  |                  |                  |               |
{ ---------------+------------------+------------------+------------------+------------------+---------------+
{ *     count is the abreviation for unconfirmed_expedited_requests.
{ **    max is the abreviation for max_unconfirmed_expedited_reqs.
{ ***   indicates (the current state of the fsm)->(the state the fsm will become after processing the request
{             or the indication)
{ ****  indicates an error condition on a request.  No state change occurs.
{ ***** indicates that the peer has responded unexpectedly.  The transport access agent will break the
{             connection.  The state will effectivly become nlc$ta_closed.

?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc nae$osi_internal_interfaces
*copyc nat$data_length
*copyc nat$osi_network_address
*copyc nat$osi_transport_address
*copyc nat$osi_transport_sap_selector
*copyc nat$ta_alternate_protocol_class
*copyc nat$ta_preferred_protocol_class
*copyc nlc$smaa_versions
*copyc nlc$ta_data_lengths
*copyc nlt$sm_protocol_data_unit
*copyc nlt$cc_interface
*copyc nlt$ta_aggregate_message
*copyc nlt$ta_connection
*copyc nlt$ta_event
*copyc nlt$ta_inventory_report
*copyc nlt$ta_protocol_data_unit
*copyc nlt$ta_sap_selector
*copyc oss$job_paged_literal
*copyc ost$status
?? POP ??
*copyc i#move
*copyc nap$condition_handler_trace
*copyc nap$namve_system_error
*copyc nlp$bm_add_message_prefix
*copyc nlp$bm_create_message
*copyc nlp$bm_extract_message_prefix
*copyc nlp$bm_copy_message
*copyc nlp$bm_get_message_length
*copyc nlp$bm_release_message
*copyc nlp$cc_accept_connection
*copyc nlp$cc_disconnect
*copyc nlp$cc_initialize_template
*copyc nlp$cc_report_undelivered_data
*copyc nlp$cc_request_connection
*copyc nlp$cc_send_aggregate_message
*copyc nlp$cc_send_expedited_data
*copyc nlp$cl_activate_layer
*copyc nlp$cl_deactivate_layer
*copyc nlp$cl_get_connection_processor
*copyc nlp$cl_get_layer_connection
*copyc nlp$cl_get_sap_processor
*copyc nlp$cl_initialize_template
*copyc nlp$get_nonexclusive_access
*copyc nlp$release_nonexclusive_access
*copyc nlp$sm_select_device
*copyc osp$add_to_locked_variable
*copyc osp$append_status_integer
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$increment_locked_variable
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc pmp$log
*copyc nav$global_osi_statistics
*copyc nav$network_procedures
*copyc nlv$bm_null_message_id
*copyc nlv$configured_network_devices
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  CONST

{ Max_unconfirmed_expedited_reqs is the number of unconfirmed expedited data requests
{ that the transport access agent will allow to be outstanding.

    max_unconfirmed_expedited_reqs = 1,
    null_osi_8073_disconnect_reason = 0;

  VAR
    initial_connection: [STATIC, READ, oss$job_paged_literal] nlt$ta_connection := [
          {accumulated_message_buffers =} 0,
          {event_processor =} nac$nil,
          {state =} nlc$ta_closed,
          {unconfirmed_expedited_requests =} 0,
          {process_expedited_data =} TRUE,
          {expedited_data_allowed =} FALSE
           ];

?? OLDTITLE ??
?? NEWTITLE := '[inline] F$CONNECTION_CLASS', EJECT ??

{ A priority greater than nlc$ta_highest_priority will be be given the lowest priority.

  FUNCTION [INLINE] f$connection_class
    (    priority: nlt$ta_priority): nlt$cc_connection_class;

    IF (priority > 8) AND (priority <= nlc$ta_highest_priority) THEN
      f$connection_class := nlc$cc_priority_class;
    ELSE
      f$connection_class := nlc$cc_normal_class;
    IFEND;

  FUNCEND f$connection_class;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$ta_accept_connection', EJECT ??
*copy nlh$ta_accept_connection

  PROCEDURE [XDCL] nlp$ta_accept_connection
    (    cl_connection { input, output } : ^nlt$cl_connection;
         checksum: boolean;
         data { input, output } : nlt$bm_message_id;
         expedited_data: boolean;
         priority: nlt$ta_priority;
         quality_of_service: ^nlt$ta_quality_of_service;
     VAR status: ost$status);

    VAR
      accept_data: nlt$bm_message_id,
      connection: ^nlt$ta_connection,
      data_length: integer,
      i: integer,
      layer_active: boolean,
      pdu_header: nlt$ta_connect_response_pdu,
      quality_of_service_length: nlt$ta_quality_of_service_len;

    status.normal := TRUE;
    accept_data := data;

{ Validate data.

    nlp$bm_get_message_length (accept_data, data_length);
    IF data_length <= nlc$ta_maximum_accept_data_len THEN
      nlp$cl_get_layer_connection (nlc$osi_transport_access_agent, cl_connection, layer_active, connection);
      IF layer_active THEN
        IF connection^.state = nlc$ta_connect_response_wait THEN

{ Quality of service has not been defined for the COS EVENT.
{ Calculate quality of service length.

          quality_of_service_length := 0;
{         IF quality_of_service <> NIL THEN
{           FOR i := LOWERBOUND (quality_of_service^) TO UPPERBOUND (quality_of_service^) DO
{             quality_of_service_length := quality_of_service_length +
{                   #SIZE (nlt$ta_quality_of_service_code) + #SIZE (nlt$ta_qual_of_serv_value_len) +
{                   quality_of_service^ [i].length;
{           FOREND;
{         IFEND;

{ Build connect response pdu.

          pdu_header.kind := nlc$ta_connect_response;
          pdu_header.length := #SIZE (nlt$ta_connect_response_pdu) + quality_of_service_length;
          pdu_header.checksum := checksum;
          pdu_header.expedited_data := expedited_data;
          pdu_header.priority := priority;
          pdu_header.quality_of_service_length := quality_of_service_length;

{ Add quality of service when it is defined.

          nlp$bm_add_message_prefix (^pdu_header, pdu_header.length, accept_data);

          nlp$cc_accept_connection (cl_connection, f$connection_class(priority), accept_data, status);
          IF status.normal THEN
            connection^.state := nlc$ta_open;

{ If the connect indication previously received had expedited data equal to FALSE
{ the expedited data on this request is ignored.

            IF connection^.expedited_data_allowed THEN
              connection^.expedited_data_allowed := expedited_data;
            IFEND;
          IFEND;

{ NOTE it is up to the lower layer to release message buffers if the request fails.

        ELSE { Nlp$ta_accept_connection request not expected.
          nlp$bm_release_message (accept_data);
          osp$set_status_condition ( nae$ta_accept_conn_not_pending,  status);
        IFEND;
      ELSE { NOT layer_active.
        nlp$bm_release_message (accept_data);
        osp$set_status_condition ( nae$ta_connection_terminated,  status);
      IFEND;
    ELSE { Invalid data.
      nlp$bm_release_message (accept_data);
      osp$set_status_condition ( nae$ta_accept_data_length_error,  status);
    IFEND;
  PROCEND nlp$ta_accept_connection;
?? OLDTITLE ??
*if false
?? NEWTITLE := '[XDCL] nlp$ta_close_sap', EJECT ??
*copy nlh$ta_close_sap

  PROCEDURE [XDCL] nlp$ta_close_sap
    (    sap: nlt$ta_sap_selector;
     VAR status: ost$status);

    status.normal := TRUE;

{ Note this request is a noop.  This requests exists for symmetry i.e. there is an open
{ request so for symmetry there should be a close.

{There is an inline version of this request.

  PROCEND nlp$ta_close_sap;
?? OLDTITLE ??
*ifend
?? NEWTITLE := '[XDCL] nlp$ta_connect_event_processor', EJECT ??
*copy nlh$ta_connect_event_processor

  PROCEDURE [XDCL] nlp$ta_connect_event_processor
    (    cl_connection { input, output } : ^nlt$cl_connection;
         event { input, output } : nlt$cc_event;
     VAR inventory_report: integer);

    VAR
      bytes_extracted: 0 .. 0ffff(16),
      connection: ^nlt$ta_connection,
      data_length: integer,
      event_processor: nlt$cl_event_processor,
      ignore_bytes_moved: nat$data_length,
      ignore_layer_active: boolean,
      ignore_status: ost$status,
      network_address: ^nat$osi_network_address,
      network_address_length: ^nat$osi_network_address_length,
      pdu: ^SEQ ( * ),
      pdu_header: nlt$ta_connect_indication_pdu,
      quality_of_service_length: ^nlt$ta_quality_of_service_len,
      ta_inventory_report: nlt$ta_inventory_report,
      transport_event: nlt$ta_event,
      transport_sap_selector: ^nat$osi_transport_sap_selector;

?? NEWTITLE := 'disconnect' ??

    PROCEDURE disconnect
      (    reason: nlt$ta_disconnect_reason);

      VAR
        data: array [1 .. 1] of nat$data_fragment,
        message: nlt$bm_message_id,
        pdu_header: nlt$ta_disconnect_request_pdu;

      pdu_header.length := #SIZE (nlt$ta_disconnect_request_pdu);
      pdu_header.kind := nlc$ta_disconnect_request;
      pdu_header.proprietary_reason := reason;
      data [1].address := ^pdu_header;
      data [1].length := #SIZE (pdu_header);
      nlp$bm_create_message (data, message, ignore_status);
      nlp$cc_disconnect (cl_connection, message, ignore_status);
      nlp$bm_release_message (transport_event.osi_connect.data);

    PROCEND disconnect;
?? OLDTITLE, EJECT ??

{ This procedure will process only cc connect events.

    IF event.kind = nlc$cc_connect_event THEN

{ Validate pdu.

      transport_event.kind := nlc$ta_connect_event;
      transport_event.osi_connect.data := event.connect.data;
      nlp$bm_get_message_length (transport_event.osi_connect.data, data_length);
      IF data_length >= #SIZE (nlt$ta_connect_indication_pdu) THEN

{ Extract the fixed portion of the pdu header.

        nlp$bm_extract_message_prefix (^pdu_header, #SIZE (pdu_header), transport_event.osi_connect.data,
              ignore_bytes_moved);
        IF pdu_header.kind = nlc$ta_connect_indication THEN
          IF (data_length >= pdu_header.length) AND (pdu_header.length >
                (#SIZE (nlt$ta_connect_indication_pdu) + pdu_header.source_transport_sap_length)) THEN
            bytes_extracted := #SIZE (nlt$ta_connect_indication_pdu);
            PUSH pdu: [[REP (pdu_header.length - bytes_extracted) OF cell]];
            RESET pdu;

{ Extract the variable portion of the pdu header.

            nlp$bm_extract_message_prefix (pdu, #SIZE (pdu^), transport_event.osi_connect.data,
                  ignore_bytes_moved);

{ Zero source transport sap length is OK.

            IF pdu_header.source_transport_sap_length > 0 THEN
              bytes_extracted := bytes_extracted + pdu_header.source_transport_sap_length;
              NEXT transport_sap_selector: [pdu_header.source_transport_sap_length] IN pdu;
              transport_event.osi_connect.source_address.transport_sap_selector := transport_sap_selector^;
              transport_event.osi_connect.source_address.transport_sap_selector_length :=
                    pdu_header.source_transport_sap_length;
            ELSE
              transport_event.osi_connect.source_address.transport_sap_selector_length := 0;
            IFEND;
            IF pdu_header.length > (bytes_extracted + #SIZE (nat$osi_network_address_length)) THEN
              bytes_extracted := bytes_extracted + #SIZE (nat$osi_network_address_length);
              NEXT network_address_length IN pdu;
              IF (network_address_length^ > 0) AND
                    (network_address_length^ <= nac$osi_max_network_address_len) AND
                    (pdu_header.length > (bytes_extracted + network_address_length^)) THEN
                bytes_extracted := bytes_extracted + network_address_length^;
                NEXT network_address: [[REP network_address_length^ OF cell]] IN pdu;
                i#move (network_address, ^transport_event.osi_connect.source_address.network_address,
                      network_address_length^);
                transport_event.osi_connect.source_address.network_address_length :=
                      network_address_length^;
                IF pdu_header.length >= (bytes_extracted + #SIZE (nlt$ta_quality_of_service_len)) THEN
                  bytes_extracted := bytes_extracted + #SIZE (nlt$ta_quality_of_service_len);
                  NEXT quality_of_service_length IN pdu;
                  IF pdu_header.length = (bytes_extracted + quality_of_service_length^) THEN
                    IF quality_of_service_length^ > 0 THEN
                      bytes_extracted := bytes_extracted + quality_of_service_length^;

{TEMPORARY}
{ Currently if there is anything in for quality of service it is ignored.

                      transport_event.osi_connect.quality_of_service := NIL
{                     NEXT transport_event.osi_connect.quality_of_service:
{                           [1 .. quality_of_service_length^] IN pdu;
                    ELSE
                      transport_event.osi_connect.quality_of_service := NIL
                    IFEND;
                    nlp$cl_activate_layer (nlc$osi_transport_access_agent, cl_connection);
                    nlp$cl_get_layer_connection (nlc$osi_transport_access_agent, cl_connection,
                          ignore_layer_active, connection);
                    connection^ := initial_connection;
                    connection^.state := nlc$ta_connect_response_wait;
                    transport_event.osi_connect.checksum := pdu_header.checksum;
                    transport_event.osi_connect.destination_transport_sap :=
                          pdu_header.destination_transport_sap;
                    transport_event.osi_connect.expedited_data := pdu_header.expedited_data;
                    connection^.expedited_data_allowed := pdu_header.expedited_data;

{ Send event to user.

                    nlp$cl_get_sap_processor (cl_connection^.application_layer,
                          nlc$osi_transport_access_agent, event_processor);
                    ta_inventory_report.changed := FALSE;
                    nav$network_procedures [event_processor.ta].ta_event_processor^
                          (cl_connection, transport_event, ta_inventory_report);
                    IF ta_inventory_report.changed THEN
                      connection^.accumulated_message_buffers := ta_inventory_report.
                            accumulated_message_buffers;
                    IFEND;
                    inventory_report := connection^.accumulated_message_buffers;
                    nlp$cl_get_connection_processor (cl_connection^.application_layer,
                          nlc$osi_transport_access_agent, event_processor);
                    connection^.event_processor := event_processor.ta;
                  ELSE { Invalid quality of service length.
                    disconnect (nlc$ta_header_length_incorrect);
                  IFEND;
                ELSE { The pdu does not contain a quality of service length.
                  disconnect (nlc$ta_header_length_incorrect);
                IFEND;
              ELSE { Invalid network address length.
                disconnect (nlc$ta_header_length_incorrect);
              IFEND;
            ELSE { The pdu does not contain all required fields.
              disconnect (nlc$ta_header_length_incorrect);
            IFEND;
          ELSE { The pdu length is greater than the actual data.
            disconnect (nlc$ta_header_length_incorrect);
          IFEND;
        ELSE { Invalid pdu header kind.
          disconnect (nlc$ta_invalid_encoding);
        IFEND;
      ELSE { Invalid pdu.  Data smaller than the connect indication pdu header.
        disconnect (nlc$ta_header_indiscernible);
      IFEND;
    ELSE { event.kind <> nlc$cc_connect_event
      nap$namve_system_error (TRUE, 'Invalid channel connection event received. ', NIL);
    IFEND;

  PROCEND nlp$ta_connect_event_processor;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$ta_disconnect_connection', EJECT ??
*copy nlh$ta_disconnect_connection

  PROCEDURE [XDCL] nlp$ta_disconnect_connection
    (    cl_connection { input, output } : ^nlt$cl_connection;
         data { input, output } : nlt$bm_message_id;
     VAR status: ost$status);

    VAR
      connection: ^nlt$ta_connection,
      data_length: integer,
      disconnect_data: nlt$bm_message_id,
      layer_active: boolean,
      pdu_header: nlt$ta_disconnect_request_pdu;

    status.normal := TRUE;
    disconnect_data := data;

{ Validate data.

    nlp$bm_get_message_length (disconnect_data, data_length);
    IF data_length <= nlc$ta_max_disconnect_data_len THEN
      nlp$cl_get_layer_connection (nlc$osi_transport_access_agent, cl_connection, layer_active, connection);
      IF layer_active THEN

{ Build pdu_header.

        pdu_header.length := #SIZE (nlt$ta_disconnect_request_pdu);
        pdu_header.kind := nlc$ta_disconnect_request;
        pdu_header.proprietary_reason := nlc$ta_user_disconnect_request;
        nlp$bm_add_message_prefix (^pdu_header, pdu_header.length, disconnect_data);
        nlp$cc_disconnect (cl_connection, disconnect_data, status);
        nlp$cl_deactivate_layer (nlc$osi_transport_access_agent, cl_connection);
      ELSE { NOT layer active.
        nlp$bm_release_message (disconnect_data);
        osp$set_status_condition ( nae$ta_connection_terminated,  status);
      IFEND;
    ELSE { Invalid data.
      nlp$bm_release_message (disconnect_data);
      osp$set_status_condition ( nae$ta_disconnect_data_len_err,  status);
    IFEND;
  PROCEND nlp$ta_disconnect_connection;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$ta_event_processor', EJECT ??
*copy nlh$ta_event_processor

  PROCEDURE [XDCL] nlp$ta_event_processor
    (    cl_connection { input, output } : ^nlt$cl_connection;
         event { input, output } : nlt$cc_event;
     VAR inventory_report: integer);

    VAR
      actual: integer,
      connect_confirm_pdu: nlt$ta_connect_confirm_pdu,
      connection: ^nlt$ta_connection,
      data: nlt$bm_message_id,
      data_length: integer,
      data_pdu: nlt$ta_data_pdu,
      disconnect_pdu: nlt$ta_disconnect_indicat_pdu,
      expedited_data_pdu: nlt$ta_expedited_data_pdu,
      layer_active: boolean,
      ignore_bytes_moved: nat$data_length,
      ignore_status: ost$status,
      quality_of_service: ^SEQ ( * ),
      ta_inventory_report: nlt$ta_inventory_report,
      transport_event: nlt$ta_event;

?? NEWTITLE := 'disconnect' ??

    PROCEDURE disconnect
      (    reason: nlt$ta_disconnect_reason;
       VAR discard_message: nlt$bm_message_id);

      VAR
        data: array [1 .. 1] of nat$data_fragment,
        message: nlt$bm_message_id,
        pdu_header: nlt$ta_disconnect_request_pdu;

      pdu_header.length := #SIZE (nlt$ta_disconnect_request_pdu);
      pdu_header.kind := nlc$ta_disconnect_request;
      pdu_header.proprietary_reason := reason;
      data [1].address := ^pdu_header;
      data [1].length := #SIZE (pdu_header);
      nlp$bm_create_message (data, message, ignore_status);
      nlp$cc_disconnect (cl_connection, message, ignore_status);
      nlp$bm_release_message (discard_message);

{ Build TAA event.

      transport_event.kind := nlc$ta_disconnect_event;
      transport_event.osi_disconnect.data := nlv$bm_null_message_id;
      transport_event.osi_disconnect.proprietary_reason := reason;
      transport_event.osi_disconnect.osi_8073_reason := null_osi_8073_disconnect_reason;

{ Send event to user.

      nav$network_procedures [connection^.event_processor].
            ta_event_processor^ (cl_connection, transport_event, ta_inventory_report);
      nlp$cl_deactivate_layer (nlc$osi_transport_access_agent, cl_connection);
    PROCEND disconnect;
?? OLDTITLE, EJECT ??

    nlp$cl_get_layer_connection (nlc$osi_transport_access_agent, cl_connection, layer_active, connection);
    IF layer_active THEN
      ta_inventory_report.changed := FALSE;
      CASE event.kind OF

{ ***  AFTER JIT CONSIDER REMOVING THE STATE CHECKS.  THE STATE SHOULD BE CONSISTENT WITH CC'S.

?? NEWTITLE := 'nlc$cc_data_event', EJECT ??

      = nlc$cc_data_event =

{ Validate pdu.

        transport_event.kind := nlc$ta_data_event;
        transport_event.osi_data.data := event.data.data;
        nlp$bm_get_message_length (transport_event.osi_data.data, data_length);
        IF data_length >= #SIZE (nlt$ta_data_pdu) THEN
          nlp$bm_extract_message_prefix (^data_pdu, #SIZE (data_pdu), transport_event.osi_data.data,
                ignore_bytes_moved);
          IF data_pdu.kind = nlc$ta_data_indication THEN
            IF (data_pdu.length = #SIZE (nlt$ta_data_pdu)) AND
                  (data_length >= (data_pdu.length + nlc$ta_minimum_data_length)) THEN
              IF connection^.state = nlc$ta_open THEN

{ Build a TAA event.

                transport_event.osi_data.end_of_message := data_pdu.end_of_message;

{ Send event to user.

                nav$network_procedures [connection^.event_processor].
                      ta_event_processor^ (cl_connection, transport_event, ta_inventory_report);
              ELSE { NOT valid state - inconsistency between TAA and cc.
{               SYSTEM_ERROR OR WHAT?
              IFEND;
            ELSE { Invalid pdu length.
              disconnect (nlc$ta_header_length_incorrect, transport_event.osi_data.data);
            IFEND;
          ELSE { Invalid pdu kind.
            disconnect (nlc$ta_invalid_encoding, transport_event.osi_data.data);
          IFEND;
        ELSE { Invalid pdu.
          disconnect (nlc$ta_header_indiscernible, transport_event.osi_data.data);
        IFEND;

{! statistics begin}
        osp$increment_locked_variable (nav$global_osi_statistics.transport_access_agent.data_pdus_received,
              0, actual);
        osp$add_to_locked_variable (nav$global_osi_statistics.transport_access_agent.total_bytes_received,
              0, data_length, actual);
{! statistics end}

?? OLDTITLE ??
?? NEWTITLE := 'nlc$cc_clear_to_send_event', EJECT ??

{ Nlc$cc_clear_to_send_event is local to NAM/VE i.e. initiated by the channel
{  connection entity.

      = nlc$cc_clear_to_send_event =

{ Build a TAA event.

        transport_event.kind := nlc$ta_clear_to_send_event;

{ Send event to user.

        nav$network_procedures [connection^.event_processor].
              ta_event_processor^ (cl_connection, transport_event, ta_inventory_report);

?? OLDTITLE ??
?? NEWTITLE := 'nlc$cc_expedited_data_event', EJECT ??

      = nlc$cc_expedited_data_event =

{ Validate pdu.

        data := event.expedited_data.data;
        IF connection^.expedited_data_allowed THEN
          nlp$bm_get_message_length (data, data_length);
          IF data_length >= #SIZE (nlt$ta_expedited_data_pdu) THEN
            nlp$bm_extract_message_prefix (^expedited_data_pdu, #SIZE (expedited_data_pdu), data,
                  ignore_bytes_moved);
            IF expedited_data_pdu.kind = nlc$ta_expedited_indication THEN
              IF (expedited_data_pdu.length = #SIZE (nlt$ta_expedited_data_pdu)) AND
                    (data_length >= (expedited_data_pdu.length + nlc$ta_min_expedited_data_len)) AND
                    (data_length <= (expedited_data_pdu.length + nlc$ta_max_expedited_data_len)) THEN
                IF connection^.state = nlc$ta_open THEN

{ Build a TAA event.

                  transport_event.kind := nlc$ta_expedited_data_event;
                  transport_event.osi_expedited_data.data := data;

{ Send event to user.

                  nav$network_procedures [connection^.event_processor].
                        ta_event_processor^ (cl_connection, transport_event, ta_inventory_report);
                ELSE { Invalid state - inconsistency between TAA and cc
{                 SYSTEM_ERROR OR WHAT?
                IFEND;
              ELSE { Invalid pdu length.
                disconnect (nlc$ta_header_length_incorrect, data);
              IFEND;
            ELSEIF expedited_data_pdu.kind = nlc$ta_expedited_confirmation THEN
              IF (data_length = expedited_data_pdu.length) AND (expedited_data_pdu.length =
                    #SIZE (nlt$ta_expedited_data_pdu)) THEN
                IF (connection^.state = nlc$ta_open) AND (connection^.unconfirmed_expedited_requests > 0) THEN
                  connection^.unconfirmed_expedited_requests :=
                                                          connection^.unconfirmed_expedited_requests - 1;

{ Expedited data requests will be allowed until max_unconfirmed_expedited_reqs is reached.  Once the max is
{ reached the unconfirmed expedited request must go to zero before additional requests will be accepted.

                  IF NOT connection^.process_expedited_data AND
                        (connection^.unconfirmed_expedited_requests = 0) THEN
                    connection^.process_expedited_data := TRUE;
                  IFEND;
                ELSEIF (connection^.state = nlc$ta_open) AND (connection^.unconfirmed_expedited_requests = 0)
                      THEN
                  disconnect (nlc$ta_expedited_not_pending, data);
                ELSE { Invalid state - inconsistency between TAA and cc.
{                 SYSTEM_ERROR OR WHAT?
                IFEND;
              ELSE { Invalid pdu length.
                disconnect (nlc$ta_header_length_incorrect, data);
              IFEND;
            ELSE { Invalid pdu header kind.
              disconnect (nlc$ta_invalid_encoding, data);
            IFEND;
          ELSE { Invalid pdu.
            disconnect (nlc$ta_header_indiscernible, data);
          IFEND;
        ELSE { IF NOT connection^.expedited_data_allowed THEN
          disconnect (nlc$ta_expedited_not_selected, data);
        IFEND;

{! statistics begin}
        osp$increment_locked_variable (nav$global_osi_statistics.transport_access_agent.
              expedited_pdus_received, 0, actual);
{! statistics end}

?? OLDTITLE ??
?? NEWTITLE := 'nlc$cc_accept_event', EJECT ??

      = nlc$cc_accept_event =

{ Validate pdu.

        transport_event.kind := nlc$ta_connect_confirm_event;
        transport_event.osi_connect_confirm.data := event.accept.data;
        nlp$bm_get_message_length (transport_event.osi_connect_confirm.data, data_length);
        IF data_length >= #SIZE (nlt$ta_connect_confirm_pdu) THEN
          nlp$bm_extract_message_prefix (^connect_confirm_pdu, #SIZE (connect_confirm_pdu),
                transport_event.osi_connect_confirm.data, ignore_bytes_moved);
          IF connect_confirm_pdu.kind = nlc$ta_connect_confirmation THEN
            IF (connect_confirm_pdu.length = (#SIZE (nlt$ta_connect_confirm_pdu) +
                  connect_confirm_pdu.quality_of_service_length)) AND
                  (data_length >= (connect_confirm_pdu.length)) AND
                  (data_length <= (connect_confirm_pdu.length + nlc$ta_maximum_accept_data_len)) THEN
              IF connection^.state = nlc$ta_connect_confirm_wait THEN
                connection^.state := nlc$ta_open;

{ Build a TAA event.

                transport_event.osi_connect_confirm.checksum := connect_confirm_pdu.checksum;
                transport_event.osi_connect_confirm.expedited_data := connect_confirm_pdu.expedited_data;
                connection^.expedited_data_allowed := connect_confirm_pdu.expedited_data;
                IF connect_confirm_pdu.quality_of_service_length > 0 THEN
                  PUSH quality_of_service: [[REP connect_confirm_pdu.quality_of_service_length OF cell]];
                  RESET quality_of_service;
                  nlp$bm_extract_message_prefix (quality_of_service,
                        connect_confirm_pdu.quality_of_service_length,
                        transport_event.osi_connect_confirm.data, ignore_bytes_moved);

{ Get quality of service.
{ TEMPORARY:  quality of service is not defined.

                  transport_event.osi_connect_confirm.quality_of_service := NIL;
                ELSE
                  transport_event.osi_connect_confirm.quality_of_service := NIL;
                IFEND;

{ Send event to user.

                nav$network_procedures [connection^.event_processor].
                      ta_event_processor^ (cl_connection, transport_event, ta_inventory_report);
              ELSE { Invalid state - inconsistency between TAA and cc.
{               SYSTEM_ERROR OR WHAT?
              IFEND;
            ELSE { Pdu length mismatch.
              disconnect (nlc$ta_header_length_incorrect, transport_event.osi_connect_confirm.data);
            IFEND;
          ELSE { Invalid pdu kind.
            disconnect (nlc$ta_invalid_encoding, transport_event.osi_connect_confirm.data);
          IFEND;
        ELSE { Invalid pdu.
          disconnect (nlc$ta_header_indiscernible, transport_event.osi_connect_confirm.data);
        IFEND;
?? OLDTITLE ??
?? NEWTITLE := 'nlc$cc_disconnect_event', EJECT ??

      = nlc$cc_disconnect_event =

{ Validate pdu.

        transport_event.kind := nlc$ta_disconnect_event;
        transport_event.osi_disconnect.data := event.disconnect.data;
        IF event.disconnect.reason = nlc$cc_dr_normal_disconnect THEN
          nlp$bm_get_message_length (transport_event.osi_disconnect.data, data_length);
          IF data_length >= #SIZE (nlt$ta_disconnect_indicat_pdu) THEN
            nlp$bm_extract_message_prefix (^disconnect_pdu, #SIZE (disconnect_pdu),
                  transport_event.osi_disconnect.data, ignore_bytes_moved);
            IF disconnect_pdu.kind = nlc$ta_disconnect_indication THEN
              IF (disconnect_pdu.length = #SIZE (nlt$ta_disconnect_indicat_pdu)) AND
                    (data_length <= #SIZE (nlt$ta_disconnect_indicat_pdu) +
                    nlc$ta_max_disconnect_data_len) THEN

{ Build a TAA event.

                transport_event.osi_disconnect.proprietary_reason := disconnect_pdu.proprietary_reason;
                transport_event.osi_disconnect.osi_8073_reason := disconnect_pdu.osi_8073_reason;
              ELSE { Invalid pdu length.

{ Build a TAA event.

                transport_event.osi_disconnect.proprietary_reason := nlc$ta_header_length_incorrect;
                transport_event.osi_disconnect.osi_8073_reason := null_osi_8073_disconnect_reason;
                nlp$bm_release_message (transport_event.osi_disconnect.data);
                transport_event.osi_disconnect.data := nlv$bm_null_message_id;
              IFEND;
            ELSE { Invalid pdu.

{ Build a TAA event.

              transport_event.osi_disconnect.proprietary_reason := nlc$ta_invalid_encoding;
              transport_event.osi_disconnect.osi_8073_reason := null_osi_8073_disconnect_reason;
              nlp$bm_release_message (transport_event.osi_disconnect.data);
              transport_event.osi_disconnect.data := nlv$bm_null_message_id;
            IFEND;
          ELSE { Invalid pdu length.

{ Build a TAA event.

            transport_event.osi_disconnect.proprietary_reason := nlc$ta_header_indiscernible;
            transport_event.osi_disconnect.osi_8073_reason := null_osi_8073_disconnect_reason;
            nlp$bm_release_message (transport_event.osi_disconnect.data);
            transport_event.osi_disconnect.data := nlv$bm_null_message_id;
          IFEND;
        ELSE { NOT nlc$cc_dr_normal_disconnect.

{ Build a TAA event.

          transport_event.osi_disconnect.proprietary_reason := event.disconnect.reason;
          transport_event.osi_disconnect.osi_8073_reason := null_osi_8073_disconnect_reason;
          nlp$bm_release_message (transport_event.osi_disconnect.data);
          transport_event.osi_disconnect.data := nlv$bm_null_message_id;
        IFEND;

{ Send event to user.

        nav$network_procedures [connection^.event_processor].
              ta_event_processor^ (cl_connection, transport_event, ta_inventory_report);
        nlp$cl_deactivate_layer (nlc$osi_transport_access_agent, cl_connection);
      ELSE { Unknown event kind.
        nap$namve_system_error (TRUE, 'Invalid channel connection event.', NIL);
      CASEND;
      IF ta_inventory_report.changed THEN
        connection^.accumulated_message_buffers := ta_inventory_report.accumulated_message_buffers;
      IFEND;
      inventory_report := connection^.accumulated_message_buffers;
    ELSE { NOT layer active.
      nap$namve_system_error (TRUE, 'Transport access agent inactive.', NIL);
    IFEND;
  PROCEND nlp$ta_event_processor;
?? OLDTITLE ??
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$ta_initialize', EJECT ??
*copy nlh$ta_initialize

  PROCEDURE [XDCL] nlp$ta_initialize
    (    application_layer: nlt$cl_application_layer;
         connect_event_processor: nat$network_procedure;
         event_processor: nat$network_procedure);

    VAR
      cl_connection_processor: nlt$cl_event_processor,
      osi_sap_processor: nlt$cl_event_processor;

    osi_sap_processor.layer := nlc$osi_transport_access_agent;
    osi_sap_processor.ta := connect_event_processor;
    cl_connection_processor.layer := nlc$osi_transport_access_agent;
    cl_connection_processor.ta := event_processor;
    nlp$cl_initialize_template (application_layer, nlc$osi_transport_access_agent,
          #SIZE (nlt$ta_connection), {maximum_protocol_header_size =}0, osi_sap_processor,
          nac$nil, cl_connection_processor, nac$nil);
    nlp$cc_initialize_template (application_layer);
  PROCEND nlp$ta_initialize;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$ta_open_sap', EJECT ??
*copy nlh$ta_open_sap

  PROCEDURE [XDCL] nlp$ta_open_sap
    (    application_layer: nlt$cl_application_layer;
         connect_event_processor: nat$network_procedure;
         event_processor: nat$network_procedure;
     VAR status: ost$status);

    VAR
      cl_connection_processor: nlt$cl_event_processor,
      osi_sap_processor: nlt$cl_event_processor;

    status.normal := TRUE;
    osi_sap_processor.layer := nlc$osi_transport_access_agent;
    osi_sap_processor.ta := connect_event_processor;
    cl_connection_processor.layer := nlc$osi_transport_access_agent;
    cl_connection_processor.ta := event_processor;
    nlp$cl_initialize_template (application_layer, nlc$osi_transport_access_agent,
          #SIZE (nlt$ta_connection), {maximum_protocol_header_size =}0, osi_sap_processor,
          nac$nil, cl_connection_processor, nac$nil);
    nlp$cc_initialize_template (application_layer);
  PROCEND nlp$ta_open_sap;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$ta_report_undelivered_data', EJECT ??

{ PURPOSE:
{   The purpose of this request is to notify the channel connection entity of the
{   amount of data stored at the application layer.

  PROCEDURE [XDCL] nlp$ta_report_undelivered_data
    (    cl_connection { input, output } : ^nlt$cl_connection;
         accumulated_message_buffers: integer);

    VAR
      connection: ^nlt$ta_connection,
      layer_active: boolean;

    nlp$cl_get_layer_connection (nlc$osi_transport_access_agent, cl_connection, layer_active, connection);
    IF layer_active THEN
      nlp$cc_report_undelivered_data (cl_connection, accumulated_message_buffers);
      connection^.accumulated_message_buffers := accumulated_message_buffers;
    IFEND;
  PROCEND nlp$ta_report_undelivered_data;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$ta_request_connection' ??
?? NEWTITLE := '    release_request_data', EJECT ??
*copy nlh$ta_request_connection

  PROCEDURE [XDCL] nlp$ta_request_connection
    (    cl_connection { input, output } : ^nlt$cl_connection;
         sap: nlt$ta_sap_selector;
         checksum: boolean;
         data { input, output } : nlt$bm_message_id;
         destination_transport_sap: nat$osi_transport_sap_selector;
         destination_network_address: nat$osi_network_address;
         cdna_destination_address: boolean;
         expedited_data: boolean;
         priority: nlt$ta_priority;
         preferred_protocol_class: nat$ta_preferred_protocol_class;
         alternate_protocol_class: nat$ta_alternate_protocol_class;
         quality_of_service: ^nlt$ta_quality_of_service;
     VAR status: ost$status);

    PROCEDURE release_request_data (
           ignore_condition: pmt$condition;
           ignore_condition_descriptor: ^pmt$condition_information;
           ignore_sa: ^ost$stack_frame_save_area;
       VAR condition_status: ost$status);

      nap$condition_handler_trace (ignore_condition, ignore_sa);
      condition_status.normal := TRUE;
      nlp$bm_release_message (request_data);

   PROCEND release_request_data;
?? OLDTITLE, EJECT ??

    VAR
      connect_data: nlt$bm_message_id,
      connection: ^nlt$ta_connection,
      data_length: integer,
      destination_device: ^nlt$device_list,
      destination_device_count: nlt$device_count,
      destination_device_version_list: ^nlt$sm_device_version_list,
      device_and_data_list: ^nlt$cc_device_and_data_list,
      device_version: nlt$sm_version,
      event_processor: nlt$cl_event_processor,
      i: integer,
      ignore_layer_active: boolean,
      ignore_status: ost$status,
      network_address: ^nat$osi_network_address,
      network_address_length: ^nat$osi_network_address_length,
      protocol_data_unit: ^SEQ ( * ),
      protocol_data_unit_size: 0 .. 0ffff(16),
      pdu_header: ^nlt$ta_connect_request_pdu,
      pdu_header_v2: ^nlt$ta_connect_request_pdu_v2,
      quality_of_service_length: ^nlt$ta_quality_of_service_len,
      quality_of_service_size: nlt$ta_quality_of_service_len,
      request_data: nlt$bm_message_id,
      transport_sap_selector: ^nat$osi_transport_sap_selector;

    status.normal := TRUE;
    request_data := data;

    IF (preferred_protocol_class <> nac$ta_preferred_class_0) AND
       (preferred_protocol_class <> nac$ta_preferred_class_4_CLNS) THEN
      nlp$bm_release_message (request_data);
      osp$set_status_condition ( nae$ta_protocol_not_supported,  status);
      RETURN;
    IFEND;

{ Validate data.

    nlp$bm_get_message_length (request_data, data_length);
    IF data_length <= nlc$ta_maximum_connect_data_len THEN
      PUSH destination_device: [1 .. nlv$configured_network_devices.network_device_count];
      PUSH destination_device_version_list: [1 .. nlv$configured_network_devices.network_device_count];

      osp$establish_block_exit_hndlr (^release_request_data);
      nlp$sm_select_device (destination_network_address, cdna_destination_address, preferred_protocol_class,
            destination_device^, destination_device_version_list^, destination_device_count, status);
      osp$disestablish_cond_handler;
      IF status.normal THEN
        nlp$cl_activate_layer (nlc$osi_transport_access_agent, cl_connection);
        nlp$cl_get_layer_connection (nlc$osi_transport_access_agent, cl_connection, ignore_layer_active,
              connection);

{ Determine the size of the quality of service.
{ Quality of service is currently undefined.

        quality_of_service_size := 0;
{       IF quality_of_service <> NIL THEN
{         FOR i := LOWERBOUND (quality_of_service^) TO UPPERBOUND (quality_of_service^) DO
{           quality_of_service_size := quality_of_service_size + #SIZE (nlt$ta_quality_of_service_code) +
{                 #SIZE (nlt$ta_qual_of_serv_value_len) + quality_of_service^ [i].length;
{         FOREND;
{       IFEND;

        PUSH device_and_data_list: [1..destination_device_count];

        FOR i := 1 to destination_device_count DO

          IF i < destination_device_count THEN
            nlp$bm_copy_message (request_data, device_and_data_list^ [i].data);
          ELSE
            device_and_data_list^ [i].data := request_data;
          IFEND;
          device_and_data_list^ [i].device_id := destination_device^ [i];

          IF destination_device_version_list^ [i] >= nlc$sm_version_2 THEN

{ Determine the size of the request pdu for version 2 (or higher) of the TAA protocol.
            protocol_data_unit_size:=#SIZE(nlt$ta_connect_request_pdu_v2)+#SIZE(destination_transport_sap)
                  + #SIZE (nat$osi_network_address_length) + #SIZE (destination_network_address) +
                  #SIZE (nlt$ta_quality_of_service_len) + quality_of_service_size;

{ Build the pdu header for version 2 (or higher) of the TAA protocol.

            PUSH protocol_data_unit: [[REP protocol_data_unit_size OF cell]];
            RESET protocol_data_unit;
            NEXT pdu_header_v2 IN protocol_data_unit;
            pdu_header_v2^.kind := nlc$ta_connect_request;
            pdu_header_v2^.length := protocol_data_unit_size;
            pdu_header_v2^.source_transport_sap := sap;
            pdu_header_v2^.checksum := checksum;
            pdu_header_v2^.expedited_data := expedited_data;
            pdu_header_v2^.priority := priority;
            pdu_header_v2^.preferred_protocol_class := preferred_protocol_class;
            pdu_header_v2^.alternate_protocol_class := alternate_protocol_class;
            pdu_header_v2^.destination_transport_sap_len := #SIZE (destination_transport_sap);
            IF #SIZE (destination_transport_sap) > 0 THEN
              NEXT transport_sap_selector: [#SIZE (destination_transport_sap)] IN protocol_data_unit;
              transport_sap_selector^ := destination_transport_sap;
            IFEND;
            NEXT network_address_length IN protocol_data_unit;
            network_address_length^ := #SIZE (destination_network_address);
            NEXT network_address: [[REP network_address_length^ OF cell]] IN protocol_data_unit;
            network_address^ := destination_network_address;
            NEXT quality_of_service_length IN protocol_data_unit;
            quality_of_service_length^ := quality_of_service_size;

{ Add quality of service when it is defined.

          ELSE  { the version of the device we are talking to is less than 2

{ Determine the size of the request pdu for the previous protocol version.

            protocol_data_unit_size := #SIZE (nlt$ta_connect_request_pdu) + #SIZE(destination_transport_sap)+
                  #SIZE (nat$osi_network_address_length) + #SIZE (destination_network_address) +
                  #SIZE (nlt$ta_quality_of_service_len) + quality_of_service_size;

{ Build the pdu header for the previous protocol version.

            PUSH protocol_data_unit: [[REP protocol_data_unit_size OF cell]];
            RESET protocol_data_unit;
            NEXT pdu_header IN protocol_data_unit;
            pdu_header^.kind := nlc$ta_connect_request;
            pdu_header^.length := protocol_data_unit_size;
            pdu_header^.source_transport_sap := sap;
            pdu_header^.checksum := checksum;
            pdu_header^.expedited_data := expedited_data;
            pdu_header^.priority := priority;
            pdu_header^.destination_transport_sap_len := #SIZE (destination_transport_sap);
            IF #SIZE (destination_transport_sap) > 0 THEN
              NEXT transport_sap_selector: [#SIZE (destination_transport_sap)] IN protocol_data_unit;
              transport_sap_selector^ := destination_transport_sap;
            IFEND;
            NEXT network_address_length IN protocol_data_unit;
            network_address_length^ := #SIZE (destination_network_address);
            NEXT network_address: [[REP network_address_length^ OF cell]] IN protocol_data_unit;
            network_address^ := destination_network_address;
            NEXT quality_of_service_length IN protocol_data_unit;
            quality_of_service_length^ := quality_of_service_size;

{ Add quality of service when it is defined.

          IFEND;

{ Merge the pdu header with the user's data

          nlp$bm_add_message_prefix (protocol_data_unit, protocol_data_unit_size,
                device_and_data_list^ [i].data);

        FOREND;

        nlp$cc_request_connection (cl_connection, device_and_data_list^, nlc$transport_access_address,
                f$connection_class (priority), status);
        IF status.normal THEN
          connection^ := initial_connection;
          connection^.state := nlc$ta_connect_confirm_wait;
          nlp$cl_get_connection_processor (cl_connection^.application_layer, nlc$osi_transport_access_agent,
                event_processor);
          connection^.event_processor := event_processor.ta;
          connection^.expedited_data_allowed := expedited_data;
        ELSE { Nlp$cc_request_connection failed.

{ NOTE: the data is released by the layer detecting the error.

          nlp$cl_deactivate_layer (nlc$osi_transport_access_agent, cl_connection);
        IFEND;
      ELSE { NOT sme status.normal.
        nlp$bm_release_message (request_data);
      IFEND;
    ELSE { Invalid data.
      nlp$bm_release_message (request_data);
      osp$set_status_condition ( nae$ta_connect_data_len_error,  status);
    IFEND;

  PROCEND nlp$ta_request_connection;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$ta_send_aggregate_message', EJECT ??
*copy nlh$ta_send_aggregate_message

  PROCEDURE [XDCL] nlp$ta_send_aggregate_message
   (    cl_connection { input, output } : ^nlt$cl_connection;
        message { input, output } : nlt$ta_aggregate_message;
    VAR status: ost$status);
?? NEWTITLE := 'release_aggregates', EJECT ??

    PROCEDURE release_aggregates (message: nlt$ta_aggregate_message);

      VAR
        release_message: nlt$bm_message_id,
        i: integer;

      FOR i := 1 TO UPPERBOUND (message) DO
        CASE message [i].kind OF
        = nlc$ta_data_event =
          release_message := message [i].data;
          nlp$bm_release_message (release_message);
        = nlc$ta_expedited_data_event =
          release_message := message [i].expedited_data;
          nlp$bm_release_message (release_message);
        ELSE
          ;
        CASEND;
      FOREND;
    PROCEND release_aggregates;
?? OLDTITLE, EJECT ??

    VAR
      actual: integer,
      aggregate_message: ^nlt$cc_aggregate_message,
      connection: ^nlt$ta_connection,
      data_count: integer,
      data_length: integer,
      expedited_data_count: integer,
      i: integer,
      layer_active: boolean,
      pdu_header: nlt$ta_data_pdu,
      total_data_length: integer;

    status.normal := TRUE;
    nlp$cl_get_layer_connection (nlc$osi_transport_access_agent, cl_connection, layer_active, connection);
    IF layer_active THEN
      IF connection^.state = nlc$ta_open THEN
        PUSH aggregate_message: [1 .. UPPERBOUND (message)];
        i := 1;
        data_count := 0;
        total_data_length := 0;
        expedited_data_count := 0;

{ Need to add the pdu header.

        WHILE (status.normal AND (i <= UPPERBOUND (message))) DO
          CASE message [i].kind OF
          = nlc$ta_data_event =
            nlp$bm_get_message_length (message [i].data, data_length);
            IF data_length >= nlc$ta_minimum_data_length THEN

{ Build data pdu.

              pdu_header.length := #SIZE (nlt$ta_data_pdu);
              pdu_header.kind := nlc$ta_data_request;
              pdu_header.end_of_message := message [i].end_of_message;

{ Merge data and pdu.

              aggregate_message^ [i].kind := nlc$cc_data_event;
              aggregate_message^ [i].data := message [i].data;
              nlp$bm_add_message_prefix (^pdu_header, pdu_header.length, aggregate_message^ [i].data);
              data_count := data_count + 1;
              total_data_length := total_data_length + pdu_header.length + data_length;
            ELSE
              osp$set_status_condition ( nae$ta_data_length_error,
                    status);
              osp$append_status_integer (osc$status_parameter_delimiter,
                    nlc$ta_minimum_data_length, 10, TRUE, status);
            IFEND;
          = nlc$ta_expedited_data_event =
            nlp$bm_get_message_length (message [i].expedited_data, data_length);
            IF (data_length >= nlc$ta_min_expedited_data_len) AND
               (data_length <= nlc$ta_max_expedited_data_len) THEN

{ Build data pdu.

              pdu_header.length := #SIZE (nlt$ta_expedited_data_pdu);
              pdu_header.kind := nlc$ta_expedited_request;

{ Merge data and pdu.

              aggregate_message^ [i].kind := nlc$cc_expedited_data_event;
              aggregate_message^ [i].expedited_data := message [i].expedited_data;
              nlp$bm_add_message_prefix (^pdu_header, pdu_header.length, aggregate_message^ [i].
                    expedited_data);
              expedited_data_count := expedited_data_count + 1;
            ELSE
              osp$set_status_condition ( nae$ta_expedited_length_error,  status);
            IFEND;
          ELSE
            osp$set_status_condition ( nae$ta_improper_aggregate_kind,  status);
          CASEND;
          i := i + 1;
        WHILEND;
        IF (status.normal) AND (expedited_data_count > 0) THEN
          IF connection^.expedited_data_allowed THEN
            IF ((connection^.unconfirmed_expedited_requests + expedited_data_count) >
                  max_unconfirmed_expedited_reqs) OR (NOT connection^.process_expedited_data) THEN
              osp$set_status_condition ( nae$ta_expedited_request_limit,  status);
            IFEND;
          ELSE { IF NOT connection^.expedited_data_allowed THEN
            osp$set_status_condition ( nae$ta_expedited_not_supported,  status);
          IFEND;
        IFEND;
        IF status.normal THEN
          nlp$cc_send_aggregate_message (cl_connection, aggregate_message^, status);
          IF status.normal THEN

{! statistics begin}
            IF data_count > 0 THEN
              osp$add_to_locked_variable (nav$global_osi_statistics.transport_access_agent.data_pdus_sent,
                    0, data_count, actual);
              osp$add_to_locked_variable (nav$global_osi_statistics.transport_access_agent.total_bytes_sent,
                    0, total_data_length, actual);
            IFEND;
            IF expedited_data_count > 0 THEN
              osp$add_to_locked_variable (nav$global_osi_statistics.transport_access_agent.
                    expedited_pdus_sent, 0, expedited_data_count, actual);
            IFEND;
{! statistics end}

            IF expedited_data_count > 0 THEN
              connection^.unconfirmed_expedited_requests :=
                              connection^.unconfirmed_expedited_requests + expedited_data_count;
              IF connection^.unconfirmed_expedited_requests = max_unconfirmed_expedited_reqs THEN
                connection^.process_expedited_data := FALSE;
              IFEND;
            IFEND;
          IFEND;
        ELSE
          release_aggregates (message);
        IFEND;
      ELSE { Invalid state.
        release_aggregates (message);
      osp$set_status_condition ( nae$ta_connect_not_established,  status);
      IFEND;
    ELSE { NOT layer_active.
      release_aggregates (message);
      osp$set_status_condition ( nae$ta_connection_terminated,  status);
    IFEND;
  PROCEND nlp$ta_send_aggregate_message;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nlp$ta_send_expedited_data', EJECT ??
*copy nlh$ta_send_expedited_data

  PROCEDURE [XDCL] nlp$ta_send_expedited_data
    (    cl_connection { input, output } : ^nlt$cl_connection;
         data { input, output } : nlt$bm_message_id;
     VAR status: ost$status);

    VAR
      actual: integer,
      connection: ^nlt$ta_connection,
      data_length: integer,
      expedited_data: nlt$bm_message_id,
      layer_active: boolean,
      pdu_header: nlt$ta_expedited_data_pdu;

    status.normal := TRUE;
    expedited_data := data;

{ Validate data.

    nlp$bm_get_message_length (data, data_length);
    IF (data_length >= nlc$ta_min_expedited_data_len) AND (data_length <= nlc$ta_max_expedited_data_len) THEN
      nlp$cl_get_layer_connection (nlc$osi_transport_access_agent, cl_connection, layer_active, connection);
      IF layer_active THEN
        IF connection^.state = nlc$ta_open THEN
          IF connection^.expedited_data_allowed THEN

{ An expedited data request (under one condition) will be sent even though a previous expedited data
{ request has not been confirmed.  The data will be sent if the number of unconfirmed requests is less than
{ max_unconfirmed_expedited_reqs and the count of unconfirmed requests has gone to zero since the last time
{ the count has been equal to max_unconfirmed_expedited_reqs.  In other words, once the count has been equal
{ to max_unconfirmed_expedited_reqs the count must decremented to zero before another expedited data request
{ will be processed.

            IF (connection^.unconfirmed_expedited_requests < max_unconfirmed_expedited_reqs) AND
               (connection^.process_expedited_data) THEN

{ Build data pdu.

              pdu_header.length := #SIZE (nlt$ta_expedited_data_pdu);
              pdu_header.kind := nlc$ta_expedited_request;

{ Merge data and pdu.

              nlp$bm_add_message_prefix (^pdu_header, pdu_header.length, expedited_data);
              nlp$cc_send_expedited_data (cl_connection, expedited_data, status);
              IF status.normal THEN
                connection^.unconfirmed_expedited_requests := connection^.unconfirmed_expedited_requests + 1;
                IF connection^.unconfirmed_expedited_requests = max_unconfirmed_expedited_reqs THEN
                  connection^.process_expedited_data := FALSE;
                IFEND;

{! statistics begin}
                osp$increment_locked_variable (nav$global_osi_statistics.transport_access_agent.
                      expedited_pdus_sent, 0, actual);
{! statistics end}

              IFEND;

{ ELSEIF (connection^.unconfirmed_expedited_requests = max_unconfirmed_expedited_reqs) OR
{    (NOT connection^.process_expedited_data) THEN

            ELSE
              nlp$bm_release_message (expedited_data);
              osp$set_status_condition ( nae$ta_expedited_request_limit,  status);
            IFEND;
          ELSE { IF NOT connection^.expedited_data_allowed THEN
            nlp$bm_release_message (expedited_data);
            osp$set_status_condition ( nae$ta_expedited_not_supported,  status);
          IFEND;
        ELSE { Invalid state.
          nlp$bm_release_message (expedited_data);
          osp$set_status_condition ( nae$ta_connect_not_established,  status);
        IFEND;
      ELSE { NOT layer_active.
        nlp$bm_release_message (expedited_data);
        osp$set_status_condition ( nae$ta_connection_terminated,  status);
      IFEND;
    ELSE { Invalid data.
      nlp$bm_release_message (expedited_data);
      osp$set_status_condition ( nae$ta_expedited_length_error,  status);
    IFEND;
  PROCEND nlp$ta_send_expedited_data;
?? OLDTITLE ??
MODEND nlm$transport_access_agent;
