view src/g23m-gprs/sndcp/sndcp_mgp.c @ 16:5ba4316fa42c

targets: initial import from Magnetite (pruned)
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 15 Jul 2018 21:40:06 +0000
parents d393cd9bb723
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GPRS (8441)
|  Modul   :  sndcp_mgp.c
+----------------------------------------------------------------------------- 
|  Copyright 2002 Texas Instruments Berlin, AG 
|                 All rights reserved. 
| 
|                 This file is confidential and a trade secret of Texas 
|                 Instruments Berlin, AG 
|                 The receipt of or possession of this file does not convey 
|                 any rights to reproduce or disclose its contents or to 
|                 manufacture, use, or sell anything it may describe, in 
|                 whole, or in part, without the specific written consent of 
|                 Texas Instruments Berlin, AG. 
+----------------------------------------------------------------------------- 
|  Purpose :  This modul is part of the entity SNDCP and implements all 
|             functions to handles the incoming primitives as described in 
|             the SDL-documentation (MG-statemachine)
+----------------------------------------------------------------------------- 
*/ 



#define ENTITY_SNDCP

/*==== INCLUDES =============================================================*/

#include "typedefs.h"    /* to get Condat data types */
#include "vsi.h"        /* to get a lot of macros */
#include "macdef.h"
#include "gsm.h"        /* to get a lot of macros */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include "dti.h"
#ifdef _SNDCP_DTI_2_
#include <string.h>
#endif /* _SNDCP_DTI_2_ */

#include "sndcp.h"        /* to get the global entity definitions */
#include "sndcp_f.h"       /* to get the functions to access the global arrays*/
#include "sndcp_mgf.h"     /* to get the local functions of service mg */
#include "sndcp_nuf.h"
#include "sndcp_nus.h"      /* to get the internal signals toservice nu */
#include "sndcp_nds.h"      /* to get the internal signals to service nd */
#include "sndcp_cias.h"      /* to get the internal signals to service cia */
#include "sndcp_sds.h"      /* to get the signals to sd service */
#include "sndcp_sus.h"      /* to get the internal signals to service su */
#include "sndcp_suas.h"      /* to get the internal signals to service sua */
#include "sndcp_sdas.h"     /* to get the signals to sda service */
#include "sndcp_sdf.h"
#include "sndcp_sdaf.h"

/*==== CONST ================================================================*/
#define TCPIP_NAME    "TCP"
/*==== LOCAL VARS ===========================================================*/

/*==== PRIVATE FUNCTIONS ====================================================*/


/*
+------------------------------------------------------------------------------
| Function    : mg_est_cnf_est_pending
+------------------------------------------------------------------------------
| Description : After receiving an ll_establish_cnf, an snsm_activate_res
|               is sent to each waiting nsapi, sua and sda, sd are notified.
|
| Parameters  : ll_establish_cnf
|
+------------------------------------------------------------------------------
*/
LOCAL void mg_est_cnf_est_pending (T_LL_ESTABLISH_CNF* ll_establish_cnf) {
  UBYTE nsapi = 0;
  USHORT sapi_state = MG_IDLE;

  TRACE_FUNCTION( "mg_est_cnf_est_pending" );

  /*
   * If MG_REL_NEC_LOC/PEER is set for the affected sapi, there will be no
   * nsapi waiting for LL_ESTABLISH_CNF.
   * LL_RELEASE_REQ must be sent.
   */
  sndcp_get_sapi_state(ll_establish_cnf->sapi, &sapi_state);
  if ((sapi_state & MG_REL_NEC_LOC) > 0) {
    PALLOC(ll_release_req, LL_RELEASE_REQ);    

    ll_release_req->sapi = ll_establish_cnf->sapi;
    ll_release_req->local = TRUE;
    sndcp_unset_sapi_state(ll_release_req->sapi, MG_REL_NEC_LOC);
    /*
     * Set the "state" for the affected and sapi to MG_REL.
     */
    sndcp_set_sapi_state(ll_establish_cnf->sapi, MG_REL);
    sndcp_unset_sapi_state(ll_establish_cnf->sapi, MG_EST);

    PSEND(hCommLLC, ll_release_req);
    return;

  }

  if ((sapi_state & MG_REL_NEC_PEER) > 0) {
    PALLOC(ll_release_req, LL_RELEASE_REQ);    

    ll_release_req->sapi = ll_establish_cnf->sapi;
    ll_release_req->local = FALSE;
    sndcp_unset_sapi_state(ll_release_req->sapi, MG_REL_NEC_PEER);
    /*
     * Set the "state" for the affected and sapi to MG_REL.
     */
    sndcp_set_sapi_state(ll_establish_cnf->sapi, MG_REL);
    sndcp_unset_sapi_state(ll_establish_cnf->sapi, MG_EST);

    PSEND(hCommLLC, ll_release_req);

    return;
  }
  if ((sapi_state & MG_XID_NEC) > 0) {
    sndcp_unset_sapi_state(ll_establish_cnf->sapi, MG_EST);
    return;
  }


  /*
   * Send an SNSM_ACTIVATE_RES to all nsapis that are waiting for
   * an LL_ESTABLISH_CNF. 
   */
  for (nsapi = 0; nsapi < SNDCP_NUMBER_OF_NSAPIS; nsapi++) {

    USHORT nsapi_state = MG_IDLE;
    USHORT local_sapi_state = MG_IDLE;
    UBYTE sapi = 0;
    UBYTE sapi_index = 0;

    sndcp_get_nsapi_state(nsapi, &nsapi_state);
    sndcp_get_nsapi_sapi(nsapi, &sapi);
    sndcp_get_sapi_state(sapi, &local_sapi_state);
    sndcp_get_sapi_index(sapi, &sapi_index);
    if ((nsapi_state & MG_ACT) > 0 &&
        (local_sapi_state & MG_XID) == 0 &&
        sapi == ll_establish_cnf->sapi) {

      
#ifndef SNDCP_UPM_INCLUDED
        mg_dti_open(nsapi);
#else
        nu_ready_ind_if_nec(nsapi);
#endif
      
      mg_send_snsm_activate_res(nsapi);

      sndcp_unset_nsapi_state(nsapi, MG_ACT);

    }
    if ((nsapi_state & MG_ACT) > 0 &&
        (local_sapi_state & MG_XID) > 0 &&
        sapi == ll_establish_cnf->sapi) {

      /*
       * Open DTI connection.
       */
#ifndef SNDCP_UPM_INCLUDED
      mg_dti_open(nsapi);
#else
      nu_ready_ind_if_nec(nsapi);
#endif

      mg_send_snsm_activate_res(nsapi);

      /*
       * Set nsapi state to MG_IDLE.
       */
      sndcp_unset_nsapi_state(nsapi, MG_ACT);

    }
    if (((local_sapi_state & MG_EST) > 0) &&
        ((nsapi_state & MG_ACT) == 0) &&
        ((local_sapi_state & MG_XID) > 0)) {
      sig_mg_nu_reset_ack(nsapi, 0, 0, FALSE);
    }
     

  } /* for (nsapi... */
  
  /*
   * All nsapis at this sapi that use ack mode, enter recovery state.
   */
  for (nsapi = 0; nsapi < SNDCP_NUMBER_OF_NSAPIS; nsapi ++) {
    UBYTE sapi = 0;
    BOOL ack = FALSE;

    sndcp_get_nsapi_sapi(nsapi, &sapi);
    sndcp_get_nsapi_ack(nsapi, &ack);
    if (ack && sapi == ll_establish_cnf->sapi) {
      sig_mg_cia_delete_npdus(nsapi);
      sig_mg_sua_delete_pdus(nsapi, sapi, FALSE);
      sig_mg_nu_recover(nsapi);
      sig_mg_nd_recover(nsapi);
    }
  } /* for all nsapis */
 
  
  sndcp_unset_sapi_state(ll_establish_cnf->sapi, MG_XID);
  sndcp_unset_sapi_state(ll_establish_cnf->sapi, MG_EST);

  sndcp_set_sapi_ack(ll_establish_cnf->sapi, TRUE);
  /*
   * Service sda may now leave state SDA_ESTABLISH_REQUESTED.
   */
  sig_mg_sda_end_est(ll_establish_cnf->sapi, TRUE);
  /*
   * Services su and sua may now leave suspend state.
   */
  sig_mg_su_resume(ll_establish_cnf->sapi);
  sig_mg_sua_resume(ll_establish_cnf->sapi);
  mg_resume_affected_nus(ll_establish_cnf->sapi);

  /* 
   * If req xid has been changed during establishment, resend it.
   */
  mg_resend_xid_if_nec(ll_establish_cnf->sapi);


} /* mg_est_cnf_est_pending() */

/*
+------------------------------------------------------------------------------
| Function    : mg_check_unset_nsapi_flow_ctrl_flag
+------------------------------------------------------------------------------
| Description : This function checks if flow control is received before PDP 
|               activation for the nsapi by checking the bit in nsapi_rcv_rdy_b4_used flag
|               for the NSAPI
|               Depending on the mode calls the corresponding function to set the 
|               nsapi recv flag to true. 
|               In all cases unset the NSAPI bit in the nsapi_rcv_rdy_b4_used flag
|
| Parameters  : affected nsapi, mode
|
+------------------------------------------------------------------------------
*/
LOCAL void mg_check_unset_nsapi_flow_ctrl_flag (UBYTE nsapi, UBYTE mode) {

  /* check if flow control is  received before PDP activation */
  if ((sndcp_data->nsapi_rcv_rdy_b4_used & (0x001 << nsapi)) > 0)
  {    
    if (mode == SNDCP_ACK)
      sda_set_nsapi_rec(nsapi, TRUE);
    else if (mode == SNDCP_UNACK)
      sd_set_nsapi_rec(nsapi, TRUE);
    
    /* Set flow control flag for the NSAPI to FALSE */
    sndcp_data->nsapi_rcv_rdy_b4_used &= ~(0x001 << nsapi);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : mg_get_downlink_data
+------------------------------------------------------------------------------
| Description : If at the given sapi an nsapi is active and using 
|               unacknowledged LLC operation mode then sig_mg_sd_getunitdata
|               (sapi) is sent.
|               If at the given sapi an nsapi is active and using 
|               acknowledged LLC operation mode then sig_mg_sda_getdata(sapi)
|               is sent.
|
| Parameters  : affected sapi
|
+------------------------------------------------------------------------------
*/
LOCAL void mg_get_downlink_data (UBYTE sapi) {

  /*
   * Are unack or ack nsapis used?
   */
  UBYTE nsapi;

  TRACE_FUNCTION( "mg_get_downlink_data" );

  for (nsapi = 0; nsapi < SNDCP_NUMBER_OF_NSAPIS; nsapi ++) {
    BOOL used = FALSE;
    
    sndcp_is_nsapi_used(nsapi, &used);
    if (used) {
      UBYTE local_sapi = 0;

      sndcp_get_nsapi_sapi(nsapi, &local_sapi);
      if (sapi == local_sapi) {
        BOOL ack = FALSE;
        USHORT nsapi_state = MG_IDLE;
        USHORT sapi_state = MG_IDLE;

        sndcp_get_nsapi_state(nsapi, &nsapi_state);
        sndcp_get_sapi_state(local_sapi, &sapi_state);
        if (((sapi_state & MG_XID) == 0) &&
            ((sapi_state & MG_EST) == 0)) {
          sndcp_get_nsapi_ack(nsapi, &ack);
          if(ack){
            sig_mg_sda_getdata(sapi, nsapi);
          } else {
            sig_mg_sd_getunitdata(sapi, nsapi);
          }
        }
      }
    }
  } /* for all nsapis */
 
} /* mg_get_downlink_data() */




/*
+------------------------------------------------------------------------------
| Function    : mg_is_comp_available
+------------------------------------------------------------------------------
| Description : is another compressor available
|
| Parameters  : sapi, ack, kind, available
|
| Note: implementation dependent!!!
|
+------------------------------------------------------------------------------
*/
LOCAL void mg_is_comp_available (UBYTE sapi,
                                 BOOL ack, 
                                 UBYTE kind, 
                                 UBYTE msid, 
                                 BOOL* available) {

  UBYTE nsapi = 0;
  USHORT nsapi_set = 0;
  UBYTE sapi_index = 0;
  BOOL local_ack = FALSE;
  T_XID_BLOCK comp_xid_block;
  U16 sapi_state = MG_IDLE;

  TRACE_FUNCTION( "mg_is_comp_available" );

  sndcp_get_sapi_index(sapi, &sapi_index);

  /*
   * Implementation dependent!
   * Currently only implemented for VJ.
   * Is requested xid block for the given SAPI holding a compressor of the
   * given kind?
   */
  if (sndcp_data->vj_count < SNDCP_MAX_VJ_COUNT) {
    *available = TRUE;
    return;
  }

  /*
   * If an XID negotiation is ongoing we have to look at the compressors in
   * req_xid_block: is a compressor requested that will be used for the same
   * LLC operation mode?
   * If no negotiation is pending, we must look at the cur_xid_block of the
   * SAPI. 
   * Note: since we have checked before that vj_count has already reached
   * SNDCP_MAX_VJ_COUNT, ther must be an appropriate compressor on the
   * used SAPI, current or requested which may also be used for this nsapi. 
   * No new compressor is available.
   */

  sndcp_get_sapi_state(sapi, &sapi_state);

  if (((sapi_state & MG_EST) == 0) &&
      ((sapi_state & MG_XID) == 0)) {

    comp_xid_block = sndcp_data->mg.cur_xid_block[sapi_index];
  } else {
    comp_xid_block = sndcp_data->mg.req_xid_block[sapi_index];
  }


  nsapi_set = comp_xid_block.vj.nsapis;
  
  if (! comp_xid_block.vj.is_set ||
      (comp_xid_block.vj.is_set && nsapi_set == 0)) {
    *available = FALSE;
    return;
  }


  /*
   * If the LLC operation mode of the cur_xid_block is not equal to the
   * given LLC operation mode, no compressor is available.
   */
  for (nsapi = 0; nsapi < SNDCP_NUMBER_OF_NSAPIS; nsapi++) {
    if (((1 << nsapi) & nsapi_set) > 0) {
      break;
    }
  }
  if(nsapi < SNDCP_NUMBER_OF_NSAPIS){
    sndcp_get_nsapi_ack(nsapi, &local_ack);
    if ((local_ack && ack) ||
        (! local_ack && ack)) {
      *available = TRUE;
      return;
    }
  } else {
    /*
     * No nsapi yet using the compressor.
     */
    *available = TRUE;
    return;
  }
  *available = FALSE;
  return;

} /* mg_is_comp_available() */

/*
+------------------------------------------------------------------------------
| Function    : mg_ll_release_to_snsm_status
+------------------------------------------------------------------------------
| Description : Converts ll_release_ind->cause to snsm_status_req->cause
|
| Parameters  : ll_release_ind->error_cause
| Return      : snsm_status_req->cause
|
+------------------------------------------------------------------------------
*/
LOCAL U16 mg_ll_release_to_snsm_status (U16 ll_cause) {


  switch (ll_cause)
  {
#ifdef SNDCP_2to1
    return ll_cause;
#else /*SNDCP_2to1*/
#ifdef SNDCP_UPM_INCLUDED
    /* Here the cause values from LL sap is converted to
     * cause values from CAUSE include SAP. This is because
     * SM expects these cause values.
     */
    case LL_RELCS_INVALID_XID:
      return CAUSE_LLC_INVALID_XID;
    case LL_RELCS_DM_RECEIVED:
      return CAUSE_LLC_DM_RECEIVED;
    case LL_RELCS_NO_PEER_RES:
      return CAUSE_LLC_NO_PEER_RES;
    case LL_RELCS_NORMAL:
      return CAUSE_LLC_NORMAL_REL;
#endif /* SNDCP_UPM_INCLUDED */    
#endif /*SNDCP_2to1*/
    default:
      return ll_cause;
  }

} /* mg_ll_release_to_snsm_status() */

/*
+------------------------------------------------------------------------------
| Function    : mg_ll_status_to_snsm_status
+------------------------------------------------------------------------------
| Description : Converts ll_status_ind->error_cause to snsm_status_req->cause
|
| Parameters  : ll_status_ind->error_cause
| Return      : snsm_status_req->cause
|
+------------------------------------------------------------------------------
*/
LOCAL U16 mg_ll_status_to_snsm_status (U16 ll_error_cause) {

  switch (ll_error_cause)
  {
#ifdef SNDCP_2to1
    return ll_error_cause;
#else /*SNDCP_2to1*/
#ifdef SNDCP_UPM_INCLUDED
    /* Here the cause values from LL sap is converted to
     * cause values from CAUSE include SAP. This is because
     * SM expects these cause values.
     */
    case LL_ERRCS_INVALID_XID:
      return CAUSE_LLC_INVALID_XID;
    case LL_ERRCS_NO_PEER_RES:
      return CAUSE_LLC_NO_PEER_RES;
#endif /* SNDCP_UPM_INCLUDED */
#endif /* SNDCP_2to1 */
    default:
      return ll_error_cause;


  }
} /* mg_ll_status_to_snsm_status() */

/*
+------------------------------------------------------------------------------
| Function    : mg_mod_ack_unack
+------------------------------------------------------------------------------
| Description : An snsm_modify_ind has indicated that the operation mode of
|               the affected nsapi changed from acknowledged to unacknowledged.
|
| Parameters  : snsm_modify_ind
|
+------------------------------------------------------------------------------
*/
#ifdef SNDCP_UPM_INCLUDED
LOCAL void mg_mod_ack_unack (T_SN_MODIFY_REQ* snsm_modify_ind) {
#else
LOCAL void mg_mod_ack_unack (T_SNSM_MODIFY_IND* snsm_modify_ind) {
#endif /*#ifdef SNDCP_UPM_INCLUDED*/

  UBYTE nsapi = 0;
  BOOL alone = TRUE;

  TRACE_FUNCTION( "mg_mod_ack_unack" );

  mg_delete_npdus(snsm_modify_ind->nsapi);
  sig_mg_nu_reset(snsm_modify_ind->nsapi, TRUE);
  /*
   * LL_RELEASE_IND expected, if this was the only ack nsapi on the affected
   * sapi.
   */
  while (nsapi < SNDCP_NUMBER_OF_NSAPIS && alone) {

    UBYTE sapi = 0;
    BOOL ack = FALSE;

    sndcp_get_nsapi_sapi(nsapi, &sapi);
    sndcp_get_nsapi_ack(nsapi, &ack);
    alone = ! (nsapi != snsm_modify_ind->nsapi &&
               sapi == snsm_modify_ind->sapi &&
               ack);

    sndcp_set_nsapi_ack(snsm_modify_ind->nsapi, FALSE);         
    nsapi++;
  }
  if (alone) {
    sndcp_data->mg.mod_expects |= MG_MOD_X_REL;
  }

} /* mg_mod_ack_unack() */

/*
+------------------------------------------------------------------------------
| Function    : mg_mod_nsapi_new
+------------------------------------------------------------------------------
| Description : An snsm_modify_ind has indicated the creation of a new NSAPI.
|               Actions similar to snsm_activate_ind are taken, but the
|               establishment is never initiated by the MS. Everything
|               concerning the given nsapi is set to acknowlegded, but the
|               LLC establishment is expected to be done by the net.
|
| Parameters  : snsm_modify_ind
|
+------------------------------------------------------------------------------
*/
#ifdef SNDCP_UPM_INCLUDED
LOCAL void mg_mod_nsapi_new (T_SN_MODIFY_REQ* snsm_modify_ind) {
#else
LOCAL void mg_mod_nsapi_new (T_SNSM_MODIFY_IND* snsm_modify_ind) {
#endif /*#ifdef SNDCP_UPM_INCLUDED*/

  /*
   * LLC mode specified?
   */
  BOOL spec = FALSE;
  /*
   * LLC mode acknowledged?
   */
  BOOL b = FALSE;

  TRACE_FUNCTION( "mg_mod_nsapi_new" );

  sndcp_set_nsapi_used(snsm_modify_ind->nsapi, TRUE);
  sndcp_set_nsapi_qos(snsm_modify_ind->nsapi, 
                      snsm_modify_ind->snsm_qos);
  sndcp_set_nsapi_sapi(snsm_modify_ind->nsapi, 
                       snsm_modify_ind->sapi);
  sndcp_set_nsapi_prio(snsm_modify_ind->nsapi, 
                       snsm_modify_ind->radio_prio);
#ifdef REL99 
  sndcp_set_nsapi_pktflowid(snsm_modify_ind->nsapi,
                       snsm_modify_ind->pkt_flow_id);
#endif /*REL99*/

  mg_is_ack(snsm_modify_ind->snsm_qos, &spec, &b);
  if (spec) { 
    if (b) {

      BOOL ack = FALSE;

      /*
       * The NSAPI will use acknowledged LLC operation mode.
       */
      sndcp_set_nsapi_ack(snsm_modify_ind->nsapi, TRUE);
      /*
       * Is the affected SAPI already in ack mode?
       */
      sndcp_get_sapi_ack(snsm_modify_ind->sapi, &ack);
      /*
       * Reset service nu to acknowledged LLC mode.
       */
#ifdef SNDCP_UPM_INCLUDED
      sig_mg_nu_reset_ack(snsm_modify_ind->nsapi, 
                          0, /*snsm_modify_ind->send_no, FIXME !!*/
                          0, /*snsm_modify_ind->rec_no,  FIXME !!*/
                          TRUE);
#else
      sig_mg_nu_reset_ack(snsm_modify_ind->nsapi, 
                          snsm_modify_ind->send_no, 
                          snsm_modify_ind->rec_no,
                          TRUE);
#endif /*#ifdef SNDCP_UPM_INCLUDED*/
    }
  }
  /*
   * LL_ESTABLISH_IND expected.
   */
  sndcp_data->mg.mod_expects |= MG_MOD_X_EST;

} /* mg_mod_nsapi_new() */

/*
+------------------------------------------------------------------------------
| Function    : mg_mod_res_if_nec
+------------------------------------------------------------------------------
| Description : The service var 'mod_expects' informs about the measures to be
| taken before an SNSM_MODIFY_RES is sent.
| If it is set to MG_MOD_X_READY then one SNSM_MODIFY_RES will be sent to each 
| of the nsapis indicated in service var 'waiting_nsapis'. 
| Sets 'waiting_nsapis' to 0.
| Sets 'mod_expects' to MG_MOD_X_NONE.
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
LOCAL void mg_mod_res_if_nec (void) {

  TRACE_FUNCTION( "mg_mod_res_if_nec" );
  
  if (sndcp_data->mg.mod_expects == MG_MOD_X_READY) {

    UBYTE nsapi = 0;

    for (nsapi = 0; nsapi < SNDCP_NUMBER_OF_NSAPIS; nsapi++) {
      if ((sndcp_data->mg.waiting_nsapis & (1 << nsapi)) > 0) {
      
#ifdef SNDCP_UPM_INCLUDED
         PALLOC (snsm_modify_res, SN_MODIFY_CNF);
#else
         PALLOC (snsm_modify_res, SNSM_MODIFY_RES);
#endif /*#ifdef SNDCP_UPM_INCLUDED*/
        snsm_modify_res->nsapi = nsapi;
#ifdef SNDCP_UPM_INCLUDED
        PSEND(hCommUPM, snsm_modify_res);
#else
        PSEND(hCommSM, snsm_modify_res);
#endif /*#ifdef SNDCP_UPM_INCLUDED*/
      }
    }
    sndcp_data->mg.waiting_nsapis = 0;
    sndcp_data->mg.mod_expects = MG_MOD_X_NONE;
  }
} /* mg_mod_res_if_nec() */

/*
+------------------------------------------------------------------------------
| Function    : mg_mod_sapi_diff
+------------------------------------------------------------------------------
| Description : An snsm_modify_ind has indicated that the new sapi for the 
|               affected context is different from the current one.
|
| Parameters  : snsm_modify_ind
|
+------------------------------------------------------------------------------
*/
#ifdef SNDCP_UPM_INCLUDED
LOCAL void mg_mod_sapi_diff (T_SN_MODIFY_REQ* snsm_modify_ind) {
#else
LOCAL void mg_mod_sapi_diff (T_SNSM_MODIFY_IND* snsm_modify_ind) {
#endif /*#ifdef SNDCP_UPM_INCLUDED*/

  BOOL old_sapi_ack = FALSE;
  BOOL alone = TRUE;
  BOOL new_context_ack = FALSE;
  BOOL new_context_ack_spec = FALSE;
  BOOL new_sapi_est = FALSE;
  UBYTE nsapi = 0;
  UBYTE old_sapi = 0;
  BOOL rec = FALSE;
  UBYTE old_sapi_index, new_sapi_index = 0;
  T_SN_UNITDATA_IND *temp_sn_unitdata = NULL;

  TRACE_FUNCTION( "mg_mod_sapi_diff" );

  /*
   * If old sapi was established and affected nsapi is only one connected
   * in ack mode: LL_RELEASE_IND expected.
   */
  sndcp_get_sapi_ack(snsm_modify_ind->sapi, &old_sapi_ack);
  while (nsapi < SNDCP_NUMBER_OF_NSAPIS && alone) {

    UBYTE sapi = 0;
    BOOL ack = FALSE;

    sndcp_get_nsapi_sapi(nsapi, &sapi);
    sndcp_get_nsapi_ack(nsapi, &ack);
    alone = ! (nsapi != snsm_modify_ind->nsapi &&
               sapi == snsm_modify_ind->sapi &&
               ack);

             
    nsapi++;
  }

  /*
   * If new qos is ack and new sapi is not yet established: expect 
   * LL_ESTABLISH_IND.
   */
  mg_is_ack(snsm_modify_ind->snsm_qos, 
            &new_context_ack_spec, 
            &new_context_ack);

  if (alone && !new_context_ack) {
    sndcp_data->mg.mod_expects |= MG_MOD_X_REL;
  }


  sndcp_get_sapi_ack(snsm_modify_ind->sapi, &new_sapi_est);
  if (! new_sapi_est) {
    sndcp_data->mg.mod_expects |= MG_MOD_X_EST;
  }

  /* Old & the New SAPI are UnAck Mode, send SNSM_MOD_CNF to SM and 
   * flowcontrol to LLC 
   */
  sndcp_get_nsapi_sapi(snsm_modify_ind->nsapi, &old_sapi);
  sndcp_get_sapi_ack(old_sapi, &old_sapi_ack);
  if(new_context_ack == old_sapi_ack && old_sapi_ack == FALSE) 
  {
    sndcp_get_sapi_index(old_sapi, &old_sapi_index);
    sndcp_data->sd = & sndcp_data->sd_base[old_sapi_index];
    sd_is_nsapi_rec(snsm_modify_ind->nsapi, &rec);

    /* Copy the Pointer, where Data on old Sapi was stored if any */
    if(sndcp_data->sd->cur_sn_unitdata_ind[snsm_modify_ind->nsapi] NEQ NULL)
    {      
      temp_sn_unitdata = 
             sndcp_data->sd->cur_sn_unitdata_ind[snsm_modify_ind->nsapi];
      sndcp_data->sd->cur_sn_unitdata_ind[snsm_modify_ind->nsapi] = NULL;
    }

    /* Set the old SAPI's NSAPI state to Non Receptive*/
    sd_set_nsapi_rec(snsm_modify_ind->nsapi, FALSE);

    /* Set the state of NSAPI associated with new SAPI same as Old SAPI */
    sndcp_get_sapi_index(snsm_modify_ind->sapi, &new_sapi_index);
    sndcp_data->sd = & sndcp_data->sd_base[new_sapi_index];
    sd_set_nsapi_rec(snsm_modify_ind->nsapi, rec);
    
    sndcp_data->mg.mod_expects = MG_MOD_X_READY;

    /* 
     * Taking care of DOWNLINK Data, when PDP is Modified 
     * from one sapi to another.
     */
    switch( sndcp_get_nsapi_rec_state(snsm_modify_ind->nsapi) )
    {
      case SD_UNACK_RECEIVE_SUBSEQUENT_SEGMENT:
        /* 
         *  If the Receiving State is SD_UNACK_RECEIVE_SUBSEQUENT_SEGMENT,
         *  this means that SNDCP has not receive the whole N-PDU, 
         *  it has received some SN-PDU's of the whole N-PDU.
         *  Hence we need to DELETE those SN-PDU's since PDP gets modified.
         */
        sig_mg_cia_delete_npdus(snsm_modify_ind->nsapi);
        sndcp_set_nsapi_rec_state(snsm_modify_ind->nsapi,
                                          SD_UNACK_RECEIVE_FIRST_SEGMENT);
        break;

       case SD_UNACK_WAIT_NSAPI:
        /* 
         *  If the Receiving State is SD_UNACK_WAIT_NSAPI, this means that
         *  SNDCP has received the whole N-PDU.
         *  Since SNDCP has not received the FLOW CONTROL from application,
         *  so it could not send the N-PDU to the application.
         *  In the meantime PDP gets modified.In this condition SNDCP needs 
         *  to copy the N-PDU from the old sapi to the modified sapi.
         */        
        if(temp_sn_unitdata NEQ NULL)
        {
          sndcp_data->sd->cur_sn_unitdata_ind[snsm_modify_ind->nsapi]
                                                        = temp_sn_unitdata;
        }
        break;

      default:
        /*
         * It is assumed that if the Receiving State is SD_UNACK_DISCARD
         * then SNDCP must have deleted all the SN-PDU,s that it might
         * have received on the old sapi. Hence we need not have to do 
         * anything here.
         */
        break;
    }

    /* Flowcontrol to LLC for new SAPI to send downlink data after 
     * PDP Modification
     */
    if(sndcp_data->sd->cur_sn_unitdata_ind[snsm_modify_ind->nsapi] EQ NULL)
    {
      sd_get_unitdata_if_nec(snsm_modify_ind->sapi);
    }
  }
  /*
   * Now switch to the new setting.
   */
  sndcp_set_nsapi_sapi(snsm_modify_ind->nsapi, snsm_modify_ind->sapi);

} /* mg_mod_sapi_diff() */

/*
+------------------------------------------------------------------------------
| Function    : mg_mod_unack_ack
+------------------------------------------------------------------------------
| Description : An snsm_modify_ind has indicated that the operation mode of
|               the affected nsapi changed from unacknowledged to acknowledged.
|
| Parameters  : snsm_modify_ind
|
+------------------------------------------------------------------------------
*/
#ifdef SNDCP_UPM_INCLUDED
LOCAL void mg_mod_unack_ack (T_SN_MODIFY_REQ* snsm_modify_ind) {
#else
LOCAL void mg_mod_unack_ack (T_SNSM_MODIFY_IND* snsm_modify_ind) {
#endif /*#ifdef SNDCP_UPM_INCLUDED*/

  BOOL ack = FALSE;

  TRACE_FUNCTION( "mg_mod_unack_ack" );

  mg_delete_npdus(snsm_modify_ind->nsapi);
  sndcp_set_nsapi_ack(snsm_modify_ind->nsapi, TRUE);
  sig_mg_nu_reset_ack(snsm_modify_ind->nsapi, 0, 0, TRUE);
  /*
   * LL_ESTABLISH_IND expected, if the sapi is not in established mode.
   */
  sndcp_get_sapi_ack(snsm_modify_ind->sapi, &ack);
  if (! ack) {
    sndcp_data->mg.mod_expects |= MG_MOD_X_EST;
  }
} /* mg_mod_unack_ack() */


/*
+------------------------------------------------------------------------------
| Function    : mg_start_re_est_timer
+------------------------------------------------------------------------------
| Description : According to GSM 4.65, 6.2.1.4, starts re-establishment timer
|
| Parameters  : affected sapi
|
+------------------------------------------------------------------------------
*/
LOCAL void mg_start_re_est_timer (UBYTE sapi) {
  UBYTE sapi_index = 0;

  TRACE_FUNCTION( "mg_start_re_est_timer" );

  sndcp_get_sapi_index(sapi, &sapi_index);
  vsi_t_start(SNDCP_handle, sapi_index, MG_RE_EST_TIME);

} /* mg_start_re_est_timer() */




/*==== PUBLIC FUNCTIONS =====================================================*/


/*
+------------------------------------------------------------------------------
| Function    : mg_exp_re_est_timer
+------------------------------------------------------------------------------
| Description : Re establishment timer has expired
|
| Parameters  : sapi_index
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_exp_re_est_timer (UBYTE sapi_index)
{ 
  TRACE_FUNCTION( "mg_exp_re_est_timer" );

  sndcp_data->su = & sndcp_data->su_base[sapi_index];
#ifdef SNDCP_UPM_INCLUDED
  mg_re_negotiate_ack(sndcp_data->su->sapi, 
                      CAUSE_SN_NO_PEER_RESPONSE);
#else
  mg_re_negotiate_ack(sndcp_data->su->sapi, 
                      LL_RELCS_NO_PEER_RES);
#endif /*#ifdef SNDCP_UPM_INCLUDED*/

} /* mg_exp_re_est_timer() */

/*
+------------------------------------------------------------------------------
| Function    : mg_ll_reset_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_RESET_IND
|
| Parameters  : *ll_reset_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_ll_reset_ind ( T_LL_RESET_IND *ll_reset_ind )
{ 
  UBYTE nsapi = 0;
  UBYTE sapi_index = 0;
  BOOL  ack = FALSE;
  UBYTE sapi = 0;

  TRACE_FUNCTION( "mg_ll_reset_ind" );
  
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
      for (nsapi = 0; nsapi < SNDCP_NUMBER_OF_NSAPIS;nsapi++) {
        BOOL used = 0;

        sndcp_is_nsapi_used(nsapi, &used);
        if (! used) {
          continue;
        }
        sig_mg_nu_reset_ind(nsapi);
        sig_mg_nu_suspend(nsapi);

        sndcp_get_nsapi_sapi(nsapi, &sapi);
        sndcp_get_nsapi_ack(nsapi, &ack);

        if (ack) {
          sig_mg_sua_delete_pdus(nsapi, sapi, FALSE);
          sig_mg_sda_reset_ind(nsapi);
          sig_mg_nd_suspend(nsapi);
          sndcp_set_nsapi_state(nsapi, MG_SEQ);
          /* Set the flag as LL_ESTB_IND is expected 
           * before resend of buffered NPDU 
           */
          sndcp_set_sapi_state(sapi, MG_EST_IND);
        } else {
          sig_mg_su_delete_pdus(nsapi, sapi);
          sig_mg_sd_reset_ind(nsapi);
        }
        sig_mg_nd_reset_ind(nsapi);
      }
      sig_mg_cia_reset_ind();
      /*
       * Reset pending states and xid_block.
       */
      for (sapi_index = 0; sapi_index < SNDCP_NUMBER_OF_SAPIS; sapi_index++) {
       
        sapi = (sndcp_data->sua_base[sapi_index]).sapi;
        /*
         * Reset SUA and SU services
         */
        sig_mg_sua_n201(sapi, N201_I_DEFAULT);
        sig_mg_sua_reset_ind(sapi);
        sig_mg_su_n201(sapi, N201_U_DEFAULT);
        sig_mg_su_reset_ind(sapi);
        /*
         * cnf_xid_block and req_xid_block initialized.
         */
        sndcp_reset_xid_block(&sndcp_data->mg.cnf_xid_block[sapi_index]);
        sndcp_reset_xid_block(&sndcp_data->mg.req_xid_block[sapi_index]);

        mg_reset_states_n_rej(sapi_index);
        /*
         * Init renegotiation counter and cur_xid_block with default values.
         */
        sndcp_data->mg.renego[sapi_index] = 0;

        sndcp_reset_xid_block(&sndcp_data->mg.cur_xid_block[sapi_index]);
        sig_mg_cia_new_xid (&sndcp_data->mg.cur_xid_block[sapi_index]);
      }
      sndcp_data->mg.mod_expects = MG_MOD_X_NONE;
      sndcp_data->mg.waiting_nsapis = 0;

      break;
    default:
      TRACE_ERROR( "LL_RESET_IND unexpected" );
      break;
  }
  if (ll_reset_ind != NULL) {
    PFREE (ll_reset_ind);
  }
  
} /* mg_ll_reset_ind() */



/*
+------------------------------------------------------------------------------
| Function    : mg_ll_establish_cnf
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_ESTABLISH_CNF
|
| Parameters  : *ll_establish_cnf - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_ll_establish_cnf ( T_LL_ESTABLISH_CNF *ll_establish_cnf )
{ 
  UBYTE sapi_index = 0;
  USHORT state = 0;

  TRACE_FUNCTION( "mg_ll_establish_cnf" );
  TRACE_EVENT_P1("ll_establish_cnf->n201_i: %d", ll_establish_cnf->n201_i);

  sndcp_get_sapi_index(ll_establish_cnf->sapi, &sapi_index); 
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
      sndcp_get_sapi_state(ll_establish_cnf->sapi, &state);
      if ((state & MG_EST) > 0) {

        UBYTE dec_ret = 0;
        UBYTE check_ret = 0;

        /*
         * Reset all compressors at this SAPI in ack mode.
         */
        mg_reset_comp_ack(ll_establish_cnf->sapi);
        /*
         * Set N201 values in uplink services.
         */
        sig_mg_su_n201(ll_establish_cnf->sapi, ll_establish_cnf->n201_u);
        sig_mg_sua_n201(ll_establish_cnf->sapi, ll_establish_cnf->n201_i);

        /*
         * SDL label MG_EST_CNF_EST_XID_PENDING.
         */
        mg_decode_xid(&(ll_establish_cnf->sdu), 
                      &(sndcp_data->mg.cnf_xid_block[sapi_index]), 
                      &dec_ret,
                      ll_establish_cnf->sapi);
        if (dec_ret == MG_XID_OK) 
        {
          /*
           * SDL label MG_CHECK_CNF_XID_ACK
           */
          mg_check_cnf_xid(&check_ret, ll_establish_cnf->sapi);
          if (check_ret == MG_XID_OK) 
          {

            /*
             * This is now similar to the reaction to LL_XID_CNF:
             */
            /*
             * SDL Label MG_CNF_OK_ACK
             */
            mg_set_cur_xid_block(ll_establish_cnf->sapi);
            /*
             * Reset nsapis or ntts that were assigned, but are not any more.
             */
            mg_clean_xid(ll_establish_cnf->sapi);
            /*
             * Resume suspended data transfer on sapi will be done in 
             * mg_est_cnf_est_pending(ll_establish_cnf).
             */

            mg_est_cnf_est_pending(ll_establish_cnf);
            
            sndcp_get_sapi_state(ll_establish_cnf->sapi, &state);
            if (((state & MG_XID_NEC) > 0)
                &&
                ((state & MG_REL) == 0)) {
              mg_resend_xid_if_nec(ll_establish_cnf->sapi);
            }

          } else {
            #ifdef SNDCP_UPM_INCLUDED
              mg_re_negotiate_ack(ll_establish_cnf->sapi, 
                                  CAUSE_SN_INVALID_XID);
            #else
              mg_re_negotiate_ack(ll_establish_cnf->sapi, 
                                  SNSM_RELCS_INVALID_XID);
            #endif /*#ifdef SNDCP_UPM_INCLUDED*/
          }
        } else {
          #ifdef SNDCP_UPM_INCLUDED
            mg_re_negotiate_ack(ll_establish_cnf->sapi, 
                                CAUSE_SN_INVALID_XID);  
          #else
            mg_re_negotiate_ack(ll_establish_cnf->sapi, 
                                SNSM_RELCS_INVALID_XID);  
          #endif /*#ifdef SNDCP_UPM_INCLUDED*/
        }
        break;

      } else { /* if ((state & MG_EST) > 0)  */

        PALLOC(ll_release_req, LL_RELEASE_REQ);    

        sndcp_unset_sapi_state(ll_release_req->sapi, MG_REL_NEC_PEER);
        ll_release_req->sapi = ll_establish_cnf->sapi;
        ll_release_req->local = FALSE;
        /*
         * Set the "state" for the affected sapi to MG_REL.
         */
        sndcp_set_sapi_state(ll_establish_cnf->sapi, MG_REL);

        PSEND(hCommLLC, ll_release_req);
      }
      break;
    default:
      TRACE_ERROR( "LL_ESTABLISH_CNF unexpected" );
      break;
  }

  /*
   * Establish confirm has been computed. If no new XID is pending,
   * the req_xid_block may be reset.
   */
  sndcp_get_sapi_state(ll_establish_cnf->sapi, &state);
  if (((state & MG_XID) == 0) &&
      ((state & MG_EST) == 0)) {
    sndcp_reset_xid_block(&sndcp_data->mg.req_xid_block[sapi_index]);
  }

  if (ll_establish_cnf != NULL) {
    PFREE(ll_establish_cnf);
  }

} /* mg_ll_establish_cnf() */


/*
+------------------------------------------------------------------------------
| Function    : mg_ll_status_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_STATUS_IND
|
| Parameters  : *ll_status_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_ll_status_ind ( T_LL_STATUS_IND *ll_status_ind )
{ 
  USHORT sapi_state = MG_IDLE;

  TRACE_FUNCTION( "mg_ll_status_ind" );
  
  switch( GET_STATE( MG ) )
  {
  case MG_DEFAULT:
      {
        #ifdef SNDCP_UPM_INCLUDED
         PALLOC(snsm_status_req, SN_STATUS_IND);
        #else
         PALLOC(snsm_status_req, SNSM_STATUS_REQ);
        #endif
        snsm_status_req->sapi = ll_status_ind->sapi;

#ifdef SNDCP_UPM_INCLUDED   
        snsm_status_req->ps_cause.ctrl_value = CAUSE_is_from_llc;
        snsm_status_req->ps_cause.value.llc_cause = 
#ifdef SNDCP_2to1
          mg_ll_status_to_snsm_status(ll_status_ind->ps_cause.value.llc_cause);
#else /*SNDCP_2to1*/
          mg_ll_status_to_snsm_status(ll_status_ind->error_cause);
#endif /*SNDCP_2to1*/

        PSEND(hCommUPM, snsm_status_req);

#else /*SNDCP_UPM_INCLUDED*/
        snsm_status_req->status_cause = 
        #ifdef _SNDCP_DTI_2_
          mg_ll_status_to_snsm_status(ll_status_ind->error_cause);
        #else /* _SNDCP_DTI_2_ */
          (U8)mg_ll_status_to_snsm_status(ll_status_ind->error_cause);
        #endif /* _SNDCP_DTI_2_ */

        PSEND(hCommSM, snsm_status_req);
#endif /*SNDCP_UPM_INCLUDED*/
        sndcp_get_sapi_state(ll_status_ind->sapi, &sapi_state);
        if ((sapi_state & MG_XID) != 0)
        {
          sig_mg_su_resume(ll_status_ind->sapi);
          sig_mg_sua_resume(ll_status_ind->sapi);
          mg_resume_affected_nus(ll_status_ind->sapi);
          sndcp_unset_sapi_state (ll_status_ind->sapi, MG_XID);
        }
        if ((sapi_state & MG_EST) != 0)
        {
#ifdef SNDCP_UPM_INCLUDED
          if (snsm_status_req->ps_cause.value.llc_cause == 
                                         CAUSE_LLC_NO_PEER_RES) {
#else /* SNDCP_UPM_INCLUDED */                                  
#ifdef _SNDCP_DTI_2_
          if (snsm_status_req->status_cause == LL_RELCS_NO_PEER_RES) {
#else /*_SNDCP_DTI_2_*/
          if (snsm_status_req->status_cause == SNSM_RELCS_NO_PEER_RES) {
#endif /* _SNDCP_DTI_2_*/
#endif /* SNDCP_UPM_INCLUDED */
            mg_start_re_est_timer(ll_status_ind->sapi);
          } else {
            sig_mg_su_resume(ll_status_ind->sapi);
            sig_mg_sua_resume(ll_status_ind->sapi);
            mg_resume_affected_nus(ll_status_ind->sapi);
            sndcp_unset_sapi_state (ll_status_ind->sapi, MG_EST);
          }
        }
      }
      break;
    default:
      TRACE_ERROR( "LL_STATUS_IND unexpected" );
      break;
  }

  if (ll_status_ind != NULL) {
    PFREE(ll_status_ind);
  }

} /* mg_ll_status_ind() */


/*
+------------------------------------------------------------------------------
| Function    : mg_ll_establish_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_ESTABLISH_IND
|
| Parameters  : *ll_establish_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_ll_establish_ind ( T_LL_ESTABLISH_IND *ll_establish_ind )
{ 
  USHORT sapi_state = 0;

  TRACE_FUNCTION( "mg_ll_establish_ind" );
  
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
      sndcp_unset_sapi_state(ll_establish_ind->sapi, MG_EST_IND);
      /*
       * Reset all compressors at this SAPI in ack mode.
       */
      mg_reset_comp_ack(ll_establish_ind->sapi);
      /*
       * If prim has been expected in course of modification, here it is.
       */
      sndcp_data->mg.mod_expects &= ~ MG_MOD_X_EST;
      /*
       * Do we have a collision?
       */
      sndcp_get_sapi_state(ll_establish_ind->sapi, &sapi_state);
      if ((sapi_state & MG_REL) > 0) {

        PFREE(ll_establish_ind);
        return;
      }


      if (((sapi_state & MG_XID) > 0) 
          ||
          ((sapi_state & MG_EST) > 0)) {
        /*
         * Is the establishment a re-establishment?
         */
        BOOL re = FALSE;

        sndcp_get_sapi_ack(ll_establish_ind->sapi, &re);
        if (re) {
          mg_col_re(ll_establish_ind);
        } else {
          mg_col_no_re(ll_establish_ind);
        }
      } else {
        /*
         * Is the establishment a re-establishment?
         */
        BOOL re = FALSE;

        sndcp_get_sapi_ack(ll_establish_ind->sapi, &re);
        if (re) {
          mg_no_col_re(ll_establish_ind);
        } else {
          mg_no_col_no_re(ll_establish_ind);
        }
      }
      /*
       * Now send snsm_modify_res, if expected.
       */
      mg_mod_res_if_nec();
      break;
    default:
      TRACE_ERROR( "LL_ESTABLISH_IND unexpected" );
      break;
  }
  if (ll_establish_ind != NULL) {
    PFREE(ll_establish_ind);
  }

} /* mg_ll_establish_ind() */



/*
+------------------------------------------------------------------------------
| Function    : mg_ll_release_cnf
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_RELEASE_CNF
|
| Parameters  : *ll_release_cnf - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_ll_release_cnf ( T_LL_RELEASE_CNF *ll_release_cnf )
{ 
  UBYTE nsapi = 0;
  USHORT nsapi_state = MG_IDLE;
  UBYTE sapi = 0;
  USHORT sapi_state = MG_IDLE;

  TRACE_FUNCTION( "mg_ll_release_cnf" );
  
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
      /*
       * Reset all compressors at this SAPI in ack mode.
       */
      mg_reset_comp_ack(ll_release_cnf->sapi);

      for (nsapi = 0; nsapi < SNDCP_NUMBER_OF_NSAPIS; nsapi++) {
        sndcp_get_nsapi_state(nsapi, &nsapi_state);
        sndcp_get_nsapi_sapi(nsapi, &sapi);
        sndcp_get_sapi_state(ll_release_cnf->sapi, &sapi_state);
        if (((sapi_state & MG_REL) > 0 )
            &&
            ((nsapi_state & MG_DEACT) > 0 )
            &&
            ((sapi_state & MG_XID) == 0 )) {
          /*
           * Release is now completed, negotiate XID or deactivate context.
           */
          if (sapi == ll_release_cnf->sapi) {
            BOOL nec = FALSE;

            mg_is_rel_comp_nec(nsapi, &nec);
            if (nec) {
              sndcp_set_sapi_state(sapi, MG_XID_NEC);
              sndcp_get_sapi_state(sapi, &sapi_state);
            } else {
            #ifdef SNDCP_UPM_INCLUDED
              PALLOC(snsm_deactivate_res, SN_DEACTIVATE_CNF);
              snsm_deactivate_res->nsapi = nsapi;
            #else
              PALLOC(snsm_deactivate_res, SNSM_DEACTIVATE_RES);
              snsm_deactivate_res->nsapi = nsapi;
            #endif /*#ifdef SNDCP_UPM_INCLUDED*/

              /*
               * Now the NSAPI is not in use anymore:
               */
              sndcp_set_nsapi_used(nsapi, FALSE);
              sndcp_set_nsapi_ack(nsapi, FALSE);
              /*
               * Set the "state" of the nsapi.
               */
              sndcp_unset_nsapi_state(nsapi, MG_DEACT);

#ifdef SNDCP_UPM_INCLUDED
              PSEND(hCommUPM, snsm_deactivate_res);
#else /*#ifdef SNDCP_UPM_INCLUDED*/
              PSEND(hCommSM, snsm_deactivate_res);
#endif /*#ifdef SNDCP_UPM_INCLUDED*/
            }
          }
        }
        if (((sapi_state & MG_REL) > 0 )
            &&
            ((nsapi_state & MG_DEACT) > 0 )
            &&
            ((sapi_state & MG_XID_NEC) > 0 )) {
          /*
           * Release is now completed, 
           * Remove nspi from compressor.
           */
          /*
           * Suspend uplink transfer for affected sapi.
           */
          sig_mg_su_suspend(sapi);
          sig_mg_sua_suspend(sapi);
          mg_suspend_affected_nus(sapi);
          /*
           * Negotiate possible deactivation of compressors.
           */
          mg_send_xid_req_del(sapi);
        }
      }
      sndcp_set_sapi_ack(ll_release_cnf->sapi, FALSE);
      sndcp_unset_sapi_state(ll_release_cnf->sapi, MG_REL);
      break;
    default:
      TRACE_ERROR( "LL_RELEASE_CNF unexpected" );
      break;
  }
  if (ll_release_cnf != NULL) {
    PFREE(ll_release_cnf);
  }

} /* mg_ll_release_cnf() */



/*
+------------------------------------------------------------------------------
| Function    : mg_ll_release_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_RELEASE_IND
|
| Parameters  : *ll_release_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_ll_release_ind ( T_LL_RELEASE_IND *ll_release_ind )
{ 

  USHORT sapi_state = 0;
  U8 sapi_index = 0;

  TRACE_FUNCTION( "mg_ll_release_ind" );
  
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:

      sndcp_unset_sapi_state(ll_release_ind->sapi, 
                             MG_REL_NEC_LOC + MG_REL_NEC_PEER);
      sndcp_get_sapi_state(ll_release_ind->sapi, &sapi_state);

      /*
       * Service sda may now leave state SDA_ESTABLISH_REQUESTED.
       */
      sig_mg_sda_end_est(ll_release_ind->sapi, FALSE);

#ifdef SNDCP_2to1
      if (((sapi_state & MG_EST) > 0) &&
          ((ll_release_ind->ps_cause.ctrl_value == CAUSE_is_from_llc) &&
          (ll_release_ind->ps_cause.value.llc_cause == CAUSE_LLC_NO_PEER_RES)))
#else /*SNDCP_2to1*/
      if (((sapi_state & MG_EST) > 0) &&
          (ll_release_ind->cause == LL_RELCS_NO_PEER_RES)) 
#endif /*SNDCP_2to1*/
      {

        /*
         * SNDCP waits for LL_ESTABLISH_CNF and cause is "no peer response".
         * According to GSM 4.65, 6.2.1.4 a re-establishment is tried after an
         * implementation specific amount of time.
         */
        mg_start_re_est_timer(ll_release_ind->sapi);
        PFREE(ll_release_ind);
        return;
      }

      sndcp_unset_sapi_state(ll_release_ind->sapi, MG_EST);


      if ((sapi_state & MG_REL) > 0) {

        /*
         * SNDCP waits for LL_ESTABLISH_CNF and cause is "no peer response".
         * According to GSM 4.65, 6.2.1.4 a re-establishment is tried after an
         * implementation specific amount of time.
         */
        PALLOC (ll_release_cnf, LL_RELEASE_CNF);
        ll_release_cnf->sapi = ll_release_ind->sapi;
        mg_ll_release_cnf(ll_release_cnf);
        PFREE(ll_release_ind);
        return;
      }
      
      /*
       * Reset all compressors at this SAPI in ack mode.
       */
      mg_reset_comp_ack(ll_release_ind->sapi);
      /*
       * If release has been expected in course of modification, here it is.
       */
      if ((sndcp_data->mg.mod_expects & MG_MOD_X_REL) > 0) {
        sndcp_data->mg.mod_expects -= MG_MOD_X_REL;
      }
      mg_del_comp_pdus_ack(ll_release_ind->sapi);
      sig_mg_su_resume(ll_release_ind->sapi);
      sig_mg_sua_resume(ll_release_ind->sapi);
      mg_resume_affected_nus(ll_release_ind->sapi);
#ifdef SNDCP_2to1
      if (((ll_release_ind->ps_cause.ctrl_value == CAUSE_is_from_llc)&&
           (ll_release_ind->ps_cause.value.llc_cause == CAUSE_LLC_DM_RECEIVED)) ||
          ((ll_release_ind->ps_cause.ctrl_value == CAUSE_is_from_llc)&&
           (ll_release_ind->ps_cause.value.llc_cause == CAUSE_LLC_INVALID_XID)) ||
          ((ll_release_ind->ps_cause.ctrl_value == CAUSE_is_from_llc)&&
           (ll_release_ind->ps_cause.value.llc_cause == CAUSE_LLC_NO_PEER_RES))) {
#else /*SNDCP_2to1*/
      if (ll_release_ind->cause == LL_RELCS_DM_RECEIVED ||
          ll_release_ind->cause == LL_RELCS_INVALID_XID ||
          ll_release_ind->cause == LL_RELCS_NO_PEER_RES) {
#endif /*SNDCP_2to1*/

#ifdef SNDCP_UPM_INCLUDED
        PALLOC (snsm_status_req, SN_STATUS_IND);
#ifdef SNDCP_2to1
        if((ll_release_ind->ps_cause.ctrl_value == CAUSE_is_from_llc)&&
           (ll_release_ind->ps_cause.value.llc_cause == CAUSE_LLC_DM_RECEIVED)){
#else
        if (ll_release_ind->cause == LL_RELCS_DM_RECEIVED){
#endif
          UBYTE nsapi, sapi = 0;
          USHORT nsapi_set = 0;
          for (nsapi = 0; nsapi < SNDCP_NUMBER_OF_NSAPIS; nsapi++){
            sndcp_get_nsapi_sapi(nsapi, &sapi);
            if(sapi == ll_release_ind->sapi){
              BOOL ack = FALSE;
              sndcp_get_nsapi_ack(nsapi, &ack);
              if(ack){
                nsapi_set |= (1 << nsapi); 
              }
            }
          }
          snsm_status_req->nsapi_set = nsapi_set;
        }
        snsm_status_req->sapi = ll_release_ind->sapi;
        snsm_status_req->ps_cause.ctrl_value = CAUSE_is_from_llc;
        snsm_status_req->ps_cause.value.llc_cause = 
#ifdef SNDCP_2to1
        mg_ll_release_to_snsm_status(ll_release_ind->ps_cause.value.llc_cause);
#else /*SNDCP_2to1*/
          mg_ll_release_to_snsm_status(ll_release_ind->cause); 
#endif /*SNDCP_2to1*/
        PSEND(hCommUPM, snsm_status_req);
#else  /* SNDCP_UPM_INCLUDED */
        PALLOC (snsm_status_req, SNSM_STATUS_REQ);
        snsm_status_req->sapi = ll_release_ind->sapi;
        snsm_status_req->status_cause = 
        #ifdef _SNDCP_DTI_2_
          mg_ll_release_to_snsm_status(ll_release_ind->cause); 
        #else /* _SNDCP_DTI_2_ */
          (U8)mg_ll_release_to_snsm_status(ll_release_ind->cause);
        #endif /* _SNDCP_DTI_2_ */

        PSEND(hCommSM, snsm_status_req);
#endif /*#ifdef SNDCP_UPM_INCLUDED*/


      }
      sndcp_set_sapi_ack(ll_release_ind->sapi, FALSE);
     
      /*
       * Now send snsm_modify_res, if expected.
       */
      mg_mod_res_if_nec();
      break;
    default:
      TRACE_ERROR( "LL_RELEASE_IND unexpected" );
      break;
  }
  /*
   * Establish confirm has been computed. If no new XID is pending,
   * the req_xid_block may be reset.
   */
  sndcp_get_sapi_index(ll_release_ind->sapi, &sapi_index);
  sndcp_get_sapi_state(ll_release_ind->sapi, &sapi_state);
  if (((sapi_state & MG_XID) == 0) &&
      ((sapi_state & MG_EST) == 0)) {
    sndcp_reset_xid_block(&sndcp_data->mg.req_xid_block[sapi_index]);
  }

  if (ll_release_ind != NULL) {
    PFREE(ll_release_ind);
  }

} /* mg_ll_release_ind() */



/*
+------------------------------------------------------------------------------
| Function    : mg_ll_xid_cnf
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_XID_CNF
|
| Parameters  : *ll_xid_cnf - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_ll_xid_cnf ( T_LL_XID_CNF* ll_xid_cnf )
{ 
  UBYTE dec_ret = 0;
  UBYTE check_ret = 0;
  UBYTE sapi_index = 0;

  TRACE_FUNCTION( "mg_ll_xid_cnf" );

  sndcp_get_sapi_index(ll_xid_cnf->sapi, &sapi_index);

#ifdef SNDCP_TRACE_ALL
  TRACE_EVENT("incoming xid block:");
  sndcp_trace_sdu(&ll_xid_cnf->sdu);
#endif

  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:

      sndcp_unset_sapi_state(ll_xid_cnf->sapi, MG_XID);

      mg_decode_xid(&(ll_xid_cnf->sdu), 
                    &(sndcp_data->mg.cnf_xid_block[sapi_index]), 
                    &dec_ret,
                    ll_xid_cnf->sapi);
      if (dec_ret == MG_XID_OK) {
        mg_check_cnf_xid(&check_ret, ll_xid_cnf->sapi);
        if (check_ret == MG_XID_OK) {
          USHORT sapi_state = MG_IDLE;

          /*
           * SDL Label MG_CNF_OK
           */
          mg_set_cur_xid_block(ll_xid_cnf->sapi);
          mg_xid_cnf_ok_res(ll_xid_cnf->sapi);
          /*
           * Reset nsapis or ntts that were assigned, but are not any more.
           */
          mg_clean_xid(ll_xid_cnf->sapi),
          /*
           * Set n201.
           */
          sig_mg_su_n201 (ll_xid_cnf->sapi, ll_xid_cnf->n201_u);
          sig_mg_sua_n201 (ll_xid_cnf->sapi, ll_xid_cnf->n201_i);

          /*
           * Resume suspended data transfer on sapi.
           */

          sndcp_get_sapi_state(ll_xid_cnf->sapi, &sapi_state);
          if (((sapi_state & MG_XID) == 0)
              &&
              ((sapi_state & MG_EST) == 0)) {

            sig_mg_su_resume(ll_xid_cnf->sapi);
            sig_mg_sua_resume(ll_xid_cnf->sapi);
            mg_resume_affected_nus(ll_xid_cnf->sapi);
          }

          /*
           * Now get downlink data.
           */

          mg_get_downlink_data(ll_xid_cnf->sapi);

          /*
           * XID confirm has been computed. The negotiation is finished and
           * the req_xid_block may be reset.
           */
          sndcp_get_sapi_state(ll_xid_cnf->sapi, &sapi_state);
          if (((sapi_state & MG_XID) == 0) &&
              ((sapi_state & MG_EST) == 0)) {
            sndcp_reset_xid_block(&sndcp_data->mg.req_xid_block[sapi_index]);
          }
        } else {
          mg_re_negotiate(ll_xid_cnf->sapi);
        }
      } else {
        mg_re_negotiate(ll_xid_cnf->sapi);
      }
      break;
    default:
      TRACE_ERROR( "LL_XID_CNF unexpected" );
      break;
  }
  if (ll_xid_cnf != NULL) {
    PFREE(ll_xid_cnf);
    sndcp_reset_xid_block(&sndcp_data->mg.cnf_xid_block[sapi_index]);
  }

} /* mg_ll_xid_cnf() */



/*
+------------------------------------------------------------------------------
| Function    : mg_ll_xid_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_XID_IND
|
| Parameters  : *ll_xid_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_ll_xid_ind ( T_LL_XID_IND *ll_xid_ind )
{ 
  UBYTE dec_ret = 0;
  UBYTE check_ret = 0;
  UBYTE sapi_index = 0;

  TRACE_FUNCTION( "mg_ll_xid_ind" );

  sndcp_get_sapi_index(ll_xid_ind->sapi, &sapi_index);
  
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:

      /*
       * Set N201 values in uplink services.
       */
      sig_mg_su_n201(ll_xid_ind->sapi, ll_xid_ind->n201_u);
      sig_mg_sua_n201(ll_xid_ind->sapi, ll_xid_ind->n201_i);

      TRACE_EVENT_P3("l3_valid: %d, N201_I: %d, N201_U: %d", 
                      ll_xid_ind->xid_valid, ll_xid_ind->n201_i, 
                      ll_xid_ind->n201_i);

      /*
       * If SNDCP XID block is not valid, we are ready.
       */
      if (ll_xid_ind->xid_valid == LL_XID_INVALID) {
        break;
      }
      /*
       * SNDCP XID block is valid and checked now.
       */
      mg_decode_xid(&(ll_xid_ind->sdu), 
                    &(sndcp_data->mg.ind_xid_block[sapi_index]), 
                    &dec_ret,
                    ll_xid_ind->sapi);
      if (dec_ret == MG_XID_OK) {
        mg_check_ind_xid(&check_ret, ll_xid_ind->sapi);
        if (check_ret == MG_XID_OK) {
          /*
           * Label MG_IND_OK
           */
          USHORT res_sdu_bit_len = 0;
          UBYTE ntt = 0;
          BOOL v42_rej = FALSE;
          BOOL vj_rej = FALSE;
          USHORT sapi_state = MG_IDLE;

          mg_set_res_cur_xid_block(ll_xid_ind->sapi, &res_sdu_bit_len);

          /*
           * Add the extra space for ntts with nsapis == 0.
           */
          for (ntt = 0; ntt < MG_MAX_ENTITIES; ntt++) {
            BOOL rej = FALSE;

            mg_get_sapi_dntt_rej(ll_xid_ind->sapi, ntt, &rej);
            if (rej) {
              /*
               * length of ntt octet and nsapis.
               */
              res_sdu_bit_len += 32;
              v42_rej = TRUE;
            }
            mg_get_sapi_pntt_rej(ll_xid_ind->sapi, ntt, &rej);
            if (rej) {
              /*
               * length of ntt octet and nsapis.
               */
              res_sdu_bit_len += 32;
              vj_rej = TRUE;
            }
          }
          if (! sndcp_data->mg.ind_xid_block[sapi_index].v42.is_set &&
              v42_rej) {
            /*
             * Add length of parameter type and length.
             */
            res_sdu_bit_len += 16;
          }
          if (! sndcp_data->mg.ind_xid_block[sapi_index].vj.is_set &&
              vj_rej) {
            /*
             * Add length of parameter type and length.
             */
            res_sdu_bit_len += 16;
          }

          {
            PALLOC_SDU (ll_xid_res, LL_XID_RES, res_sdu_bit_len);

            /*
             * Set sapi in ll_xid_res.
             */
            ll_xid_res->sapi = ll_xid_ind->sapi;
            /*
             * Write res_xid_block struct to sdu byte buffer. Implementation dep..
             */
            mg_set_res_xid_params(&ll_xid_res->sdu, ll_xid_ind->sapi);
            /*
             * Mark the affected nsapi and sapi as MG_XID_IDLE.
             */
            sndcp_unset_sapi_state(ll_xid_ind->sapi, MG_XID);
            sndcp_unset_sapi_state(ll_xid_ind->sapi, MG_EST);

            /*
             * Send the XID block to LLC.
             */
            
#ifdef SNDCP_RANGE_CHECK

            if(ll_xid_res EQ NULL)
            {
              TRACE_EVENT("ERROR: ll_xid_res is NULL");
            }
            else if(*((ULONG*)ll_xid_res - 7) NEQ 0)
            {
              TRACE_EVENT("ERROR in SNDCP: ll_xid_res is not allocated");
            }

#endif /* SNDCP_RANGE_CHECK */

            PSEND(hCommLLC, ll_xid_res);
          }

          /*
           * Reset nsapis or ntts that were assigned, but are not any more.
           */
          mg_clean_xid(ll_xid_ind->sapi);

          /*
           * If there was a collision and xid has not been negotiated 
           * sufficiently.
           */
          mg_resend_xid_if_nec(ll_xid_ind->sapi);
          /*
           * If activation or deactivation is pending, it will be responded if
           * no xid_req is pending.
           */
          sndcp_get_sapi_state(ll_xid_ind->sapi, &sapi_state);
          if ((sapi_state & MG_XID) == 0) {
            mg_xid_cnf_ok_res(ll_xid_ind->sapi);
          }


        } else {
          /* 
           * not (check_ret == MG_IND_XID_OK) 
           */
          /*
           * Label MG_CHECK_FAIL
           */
          USHORT res_sdu_bit_len = 0;
          UBYTE ntt = 0;
          BOOL v42_rej = FALSE;
          BOOL vj_rej = FALSE;

          /*
           * Add the extra space for ntts with nsapis == 0.
           */
          for (ntt = 0; ntt < MG_MAX_ENTITIES; ntt++) {
            BOOL rej = FALSE;

            mg_get_sapi_dntt_rej(ll_xid_ind->sapi, ntt, &rej);
            if (rej) {
              /*
               * length of ntt octet and nsapis.
               */
              res_sdu_bit_len += 32;
              v42_rej = TRUE;
            }
            mg_get_sapi_pntt_rej(ll_xid_ind->sapi, ntt, &rej);
            if (rej) {
              /*
               * length of ntt octet and nsapis.
               */
              res_sdu_bit_len += 32;
              vj_rej = TRUE;
            }
          }
          if (v42_rej) {
            /*
             * Add length of parameter type and length.
             */
            res_sdu_bit_len += 16;
          }
          if (vj_rej) {
            /*
             * Add length of parameter type and length.
             */
            res_sdu_bit_len += 16;
          }
          /*
           * Allocate response and send it.
           */
          {
            PALLOC_SDU (ll_xid_res, LL_XID_RES, res_sdu_bit_len);

            /*
             * Reset res_xid_block, ind_xid_block.
             */
            sndcp_reset_xid_block(&sndcp_data->mg.res_xid_block[sapi_index]);
            sndcp_reset_xid_block(&sndcp_data->mg.ind_xid_block[sapi_index]);
            /*
             * Set sapi in ll_xid_res.
             */
            ll_xid_res->sapi = ll_xid_ind->sapi;
            /*
             * Write res_xid_block struct to sdu byte buffer. Implementation dep..
             */
            mg_set_res_xid_params(&ll_xid_res->sdu, ll_xid_res->sapi);
            /*
             * Modify the affected sapi state.
             */
            sndcp_unset_sapi_state(ll_xid_ind->sapi, MG_XID);
            sndcp_unset_sapi_state(ll_xid_ind->sapi, MG_EST);

            /*
             * Send the XID block to LLC.
             */

#ifdef SNDCP_RANGE_CHECK

            if(ll_xid_res EQ NULL)
            {
              TRACE_EVENT("ERROR: ll_xid_res is NULL");
            }
            else if(*((ULONG*)ll_xid_res - 7) NEQ 0)
            {
              TRACE_EVENT("ERROR in SNDCP: ll_xid_res is not allocated");
            }

#endif /* SNDCP_RANGE_CHECK */

            PSEND(hCommLLC, ll_xid_res);
          }
          /*
           * If there was a collision and xid has not been negotiated 
           * sufficiently.
           */
          mg_resend_xid_if_nec(ll_xid_ind->sapi);

          /*
           * Reset nsapis or ntts that were assigned before 
           * but are not anymore.
           */ 
          mg_clean_xid(ll_xid_ind->sapi);
          /*
           * Allocate status req and send it  (label MG_SEND_STATUS_REQ).
           */
          {
#ifdef SNDCP_UPM_INCLUDED
            PALLOC (snsm_status_req, SN_STATUS_IND);
            snsm_status_req->sapi = ll_xid_ind->sapi;
            snsm_status_req->ps_cause.ctrl_value = CAUSE_is_from_sndcp;
            snsm_status_req->ps_cause.value.sn_cause = CAUSE_SN_INVALID_XID;
            PSEND(hCommUPM, snsm_status_req);
#else
            PALLOC (snsm_status_req, SNSM_STATUS_REQ);
            snsm_status_req->sapi = ll_xid_ind->sapi;
            snsm_status_req->status_cause = SNSM_RELCS_INVALID_XID;
            PSEND(hCommSM, snsm_status_req);
#endif /*#ifdef SNDCP_UPM_INCLUDED*/

          }
        } 
      } else { /* not if (dec_ret == MG_XID_OK) */
        /*
         * Reset nsapis or ntts that were assigned before 
         * but are not anymore.
         */ 
        sndcp_reset_xid_block(&sndcp_data->mg.cur_xid_block[sapi_index]);
        mg_clean_xid(ll_xid_ind->sapi);
        /*
         * Decoding of LL_XID_IND failed (label MG_SEND_STATUS_REQ).
         * Allocate status req and send it.
         */
        {
         #ifdef SNDCP_UPM_INCLUDED
          PALLOC (snsm_status_req, SN_STATUS_IND);
          snsm_status_req->sapi = ll_xid_ind->sapi;
          snsm_status_req->ps_cause.ctrl_value = CAUSE_is_from_sndcp;
          snsm_status_req->ps_cause.value.sn_cause = CAUSE_SN_INVALID_XID;
          PSEND(hCommUPM, snsm_status_req);
        #else
          PALLOC (snsm_status_req, SNSM_STATUS_REQ);
          snsm_status_req->sapi = ll_xid_ind->sapi;
          snsm_status_req->status_cause = SNSM_RELCS_INVALID_XID;
          PSEND(hCommSM, snsm_status_req);
        #endif /*#ifdef SNDCP_UPM_INCLUDED*/

        }

      }
      break;
    default:
      TRACE_ERROR( "LL_XID_IND unexpected" );
      break;
  }
  if (ll_xid_ind != NULL) {
    sndcp_reset_xid_block(&sndcp_data->mg.ind_xid_block[sapi_index]);
    PFREE(ll_xid_ind);
  }
} /* mg_ll_xid_ind() */



/*
+------------------------------------------------------------------------------
| Function    : mg_snsm_activate_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive SNSM_ACTIVATE_IND
|
| Parameters  : *snsm_activate_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
#ifdef SNDCP_UPM_INCLUDED
GLOBAL void mg_snsm_activate_ind ( T_SN_ACTIVATE_REQ *snsm_activate_ind )
#else
GLOBAL void mg_snsm_activate_ind ( T_SNSM_ACTIVATE_IND *snsm_activate_ind )
#endif /*#ifdef SNDCP_UPM_INCLUDED*/
{ 
  /*
   * is nsapi already used?
   */
  BOOL used = FALSE;
  /*
   * is LLC mode specified (TRUE) or should the subscribed one be used 
   * (FALSE)
   */
  BOOL spec = FALSE;
  /*
   * should the context use acknowledged LLC operation mode?
   */
  BOOL b = FALSE;

  TRACE_FUNCTION( "mg_snsm_activate_ind" );

#ifndef NCONFIG
  if (sndcp_data->millis > 0) {
    vsi_t_sleep(VSI_CALLER sndcp_data->millis); 
  }
#endif /* NCONFIG */
  
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
      sndcp_is_nsapi_used(snsm_activate_ind->nsapi, &used);
      if (used == FALSE) {

        USHORT sapi_state = MG_IDLE;

        sndcp_set_nsapi_state(snsm_activate_ind->nsapi, MG_ACT);
        sndcp_reset_nd_nsapi_npdu_num(snsm_activate_ind->nsapi);
        sndcp_set_nsapi_used(snsm_activate_ind->nsapi, TRUE);
        sndcp_set_nsapi_qos(snsm_activate_ind->nsapi, 
                            snsm_activate_ind->snsm_qos);
        sndcp_set_nsapi_sapi(snsm_activate_ind->nsapi, 
                             snsm_activate_ind->sapi);
        sndcp_set_nsapi_prio(snsm_activate_ind->nsapi, 
                             snsm_activate_ind->radio_prio);
#ifdef REL99  
        sndcp_set_nsapi_pktflowid(snsm_activate_ind->nsapi, 
                                  snsm_activate_ind->pkt_flow_id);
#endif /*REL 99*/

#if 0
#ifdef _SNDCP_DTI_2_
#ifndef SNDCP_UPM_INCLUDED 
        if (snsm_activate_ind->dti_direction == DTI_CHANNEL_TO_LOWER_LAYER) {
          /* new constant instead of SNSM HOME , replaced by DTI_CHANNEL_TO_LOWER_LAYER */
          sndcp_set_nsapi_direction(snsm_activate_ind->nsapi, DTI_CHANNEL_TO_LOWER_LAYER);
        } else {
          sndcp_set_nsapi_direction(snsm_activate_ind->nsapi, DTI_CHANNEL_TO_HIGHER_LAYER);
        }
      
        sndcp_set_nsapi_linkid(snsm_activate_ind->nsapi, 
                               snsm_activate_ind->dti_linkid);

        sndcp_set_nsapi_neighbor(snsm_activate_ind->nsapi, 
#ifdef _SIMULATION_
                                 (snsm_activate_ind->dti_neighbor == 
                                    0xabcdabcd 
                                  ?
                                  "PPP" 
                                  :
                                  "NULL")
#else /* _SIMULATION_ */ 
                                 (U8*)snsm_activate_ind->dti_neighbor
#endif /* _SIMULATION_ */                            
                                 );
#endif /*#ifdef SNDCP_UPM_INCLUDED*/

#else /*_SNDCP_DTI_2_*/
        if (snsm_activate_ind->dti_direction == SNSM_HOME) {
          /* new constant instead of HOME, but the comiler switch! */
          sndcp_set_nsapi_direction(snsm_activate_ind->nsapi, HOME);
        } else {
          sndcp_set_nsapi_direction(snsm_activate_ind->nsapi, NEIGHBOR);
        }
        sndcp_set_nsapi_linkid(snsm_activate_ind->nsapi, 
                               snsm_activate_ind->dti_linkid);
        sndcp_set_nsapi_neighbor(snsm_activate_ind->nsapi, 
#ifdef _SIMULATION_
                                 (snsm_activate_ind->dti_neighbor == 
                                    0xabcdabcd 
                                  ?
                                  "PPP" 
                                  :
                                  "NULL")
#else
                                 (U8*)snsm_activate_ind->dti_neighbor
#endif /* _SIMULATION_ */                            
                                 ); 
#endif /*_SNDCP_DTI_2_*/
#endif
        mg_is_ack(snsm_activate_ind->snsm_qos, &spec, &b);
        if (spec) { 
          if (b) {
            /*
             * The NSAPI will use acknowledged LLC operation mode.
             */

            BOOL ack = FALSE;
            USHORT local_sapi_state = MG_IDLE;
            BOOL comp_available = FALSE;

            /*
             * Is another compressor available?
             */
          #ifdef SNDCP_UPM_INCLUDED  
            mg_is_comp_available(snsm_activate_ind->sapi, 
                                 TRUE,
                                 SNDCP_ACK,
                                 snsm_activate_ind->comp_params.msid,
                                 &comp_available);
          #else
            mg_is_comp_available(snsm_activate_ind->sapi, 
                                 TRUE,
                                 SNDCP_ACK,
                                 snsm_activate_ind->msid,
                                 &comp_available);
          #endif /*#ifdef SNDCP_UPM_INCLUDED*/

            sndcp_set_nsapi_ack(snsm_activate_ind->nsapi, TRUE);
            /*
             * Is the affected SAPI already in ack mode or est_pending??
             */
            sndcp_get_sapi_ack(snsm_activate_ind->sapi, &ack);
            sndcp_get_sapi_state(snsm_activate_ind->sapi, &local_sapi_state);

            if ((((local_sapi_state & MG_EST) > 0)
                  ||
                  ((local_sapi_state & MG_XID) > 0))
                 &&
                 comp_available) 
            {
              sndcp_set_sapi_state(snsm_activate_ind->sapi, MG_XID_NEC);
              mg_set_new_xid_block(snsm_activate_ind);

            } else if (ack) {

               /* check if flow control is  received before PDP activation */
              mg_check_unset_nsapi_flow_ctrl_flag (snsm_activate_ind->nsapi,SNDCP_ACK);
              /*
               * If XID negotiation is not requested, respond
               * activation to SM, else send LL_XID_REQ.
               */
          #ifdef SNDCP_UPM_INCLUDED 
              if ((snsm_activate_ind->comp_params.dcomp == NAS_DCOMP_OFF &&
                   snsm_activate_ind->comp_params.hcomp == NAS_HCOMP_OFF) ||
                  ! comp_available)               {
            #else
              if ((snsm_activate_ind->dcomp == SNSM_COMP_NEITHER_DIRECT &&
                   snsm_activate_ind->hcomp == SNSM_COMP_NEITHER_DIRECT) ||
                  ! comp_available)               {
            #endif /*#ifdef SNDCP_UPM_INCLUDED*/

                /*
                 * If est_pending, the res is sent after est_cnf.
                 */

                /*
                 * Reset service nu to acknowledged LLC mode.
                 */
                sig_mg_nu_reset_ack(snsm_activate_ind->nsapi, 0, 0, FALSE);
                /*
                 * Open DTI connection.
                 */
#ifndef SNDCP_UPM_INCLUDED
                mg_dti_open(snsm_activate_ind->nsapi);
#else
                nu_ready_ind_if_nec(snsm_activate_ind->nsapi);
#endif

                /*
                 * 
                 */
                sig_mg_sda_getdata(snsm_activate_ind->sapi, snsm_activate_ind->nsapi);
                /*
                 * Send response
                 */
                mg_send_snsm_activate_res(snsm_activate_ind->nsapi);

                /*
                 * unsetting the ACT-state
                 */
                sndcp_unset_nsapi_state(snsm_activate_ind->nsapi, MG_ACT);                

              } else { /* if XID negotiation necessary */
                USHORT punct_sapi_state = MG_IDLE;

                /*
                 * Increment number of requested compressors.
                 */
                sndcp_data->vj_count++;
                /*
                 * Set the N-PDU number in the affected nu instance to 0.
                 */
                sig_mg_nu_reset_ack(snsm_activate_ind->nsapi, 0, 0, TRUE);
                /*
                 * Uplink data transfer on SAPI is completely suspended.
                 */
                sig_mg_su_suspend(snsm_activate_ind->sapi);
                sig_mg_sua_suspend(snsm_activate_ind->sapi);
                mg_suspend_affected_nus(snsm_activate_ind->sapi);
                /*
                 * Send prim or store requested compression.
                 */
                sndcp_get_sapi_state(snsm_activate_ind->sapi, 
                                     &punct_sapi_state);
                mg_send_xid_req(snsm_activate_ind);
 
              } /* if XID negotiation necessary */
            } else {
              /*
               * Is XID negotiation necessary?
               */
          #ifdef SNDCP_UPM_INCLUDED  
              if ((snsm_activate_ind->comp_params.dcomp == NAS_DCOMP_OFF &&
                   snsm_activate_ind->comp_params.hcomp == NAS_HCOMP_OFF) ||
                   sndcp_data->vj_count == SNDCP_MAX_VJ_COUNT)
            #else
              if ((snsm_activate_ind->dcomp == SNSM_COMP_NEITHER_DIRECT &&
                   snsm_activate_ind->hcomp == SNSM_COMP_NEITHER_DIRECT) ||
                   sndcp_data->vj_count == SNDCP_MAX_VJ_COUNT)
            #endif /*#ifdef SNDCP_UPM_INCLUDED*/
              {
                /*
                 * Ack mode, sapi not yet established.
                 * No XID requested.
                 */
                PALLOC_SDU(ll_establish_req, LL_ESTABLISH_REQ, 0);

                /*
                 * Reset service nu to acknowledged LLC mode.
                 */
                sig_mg_nu_reset_ack(snsm_activate_ind->nsapi, 0, 0, TRUE);

                ll_establish_req->sapi = snsm_activate_ind->sapi;
                /*
                 * Set the establishment states of sapi
                 */
                sndcp_set_sapi_state(snsm_activate_ind->sapi, MG_EST);
                /*
                 * Uplink data transfer on SAPI is completely suspended.
                 */
                sig_mg_su_suspend(snsm_activate_ind->sapi);
                sig_mg_sua_suspend(snsm_activate_ind->sapi);
                mg_suspend_affected_nus(snsm_activate_ind->sapi);

                /*
                 * Send prim to LLC.
                 */
                sndcp_set_nsapi_rec_state(snsm_activate_ind->nsapi, SDA_ESTABLISH_REQUESTED);

#ifdef SNDCP_RANGE_CHECK

                if(ll_establish_req EQ NULL)
                {
                  TRACE_EVENT("ERROR: ll_establish_req is NULL");
                }
                else if(*((ULONG*)ll_establish_req - 7) NEQ 0)
                {
                  TRACE_EVENT
                    ("ERROR in SNDCP: ll_establish_req is not allocated");
                }

#endif /* SNDCP_RANGE_CHECK */

                PSEND(hCommLLC, ll_establish_req);
              } else {

                UBYTE sapi_index = 0;

                /*
                 * Ack mode, sapi not yet established.
                 * XID requested.
                 */
                PALLOC_SDU(ll_establish_req, 
                           LL_ESTABLISH_REQ, 
                           SNDCP_XID_BLOCK_BIT_LEN);

                /*
                 * Increment number of requested compressors.
                 */
                sndcp_data->vj_count++;

                sndcp_get_sapi_index(snsm_activate_ind->sapi, &sapi_index);
                /*
                 * Reset service nu to acknowledged LLC mode.
                 */
                sig_mg_nu_reset_ack(snsm_activate_ind->nsapi, 0, 0, TRUE);

                ll_establish_req->sapi = snsm_activate_ind->sapi;
                /*
                 * Write data from snsm_activate_ind to service variable req_xid_block.
                 */

                mg_set_req_xid_block(snsm_activate_ind);
                /*
                 * Fill the XID block. Implementation dependent!!!
                 */
                mg_set_xid_params(ll_establish_req->sapi,
                                  &ll_establish_req->sdu,
                                  sndcp_data->mg.req_xid_block[sapi_index]);

                /*
                 * Set the establishment states of sapi
                 */
                sndcp_set_sapi_state(snsm_activate_ind->sapi, MG_EST);
                /*
                 * Uplink data transfer on SAPI is completely suspended.
                 */
                sig_mg_su_suspend(snsm_activate_ind->sapi);
                sig_mg_sua_suspend(snsm_activate_ind->sapi);
                mg_suspend_affected_nus(snsm_activate_ind->sapi);

                /*
                 * Send prim to LLC.
                 */
                sndcp_set_nsapi_rec_state(snsm_activate_ind->nsapi, SDA_ESTABLISH_REQUESTED);

#ifdef SNDCP_RANGE_CHECK

                if(ll_establish_req EQ NULL)
                {
                  TRACE_EVENT("ERROR: ll_establish_req is NULL");
                }
                else if(*((ULONG*)ll_establish_req - 7) NEQ 0)
                {
                  TRACE_EVENT
                    ("ERROR in SNDCP: ll_establish_req is not allocated");
                }

#endif /* SNDCP_RANGE_CHECK */

                PSEND(hCommLLC, ll_establish_req);
              }
            }
          } else { 
            /*
             * The NSAPI will not use acknowledged LLC operation mode.
             */

            /*
             * Is XID negotiation necessary?
             */
             
             /* check if flow control is  received before PDP activation */
            mg_check_unset_nsapi_flow_ctrl_flag (snsm_activate_ind->nsapi,SNDCP_UNACK);


#ifdef TI_PS_FF_V42BIS
          #ifdef SNDCP_UPM_INCLUDED  
            if ((snsm_activate_ind->comp_params.hcomp == NAS_HCOMP_NEITHER_DIRECT
                 ||
                 sndcp_data->vj_count >= SNDCP_MAX_VJ_COUNT)
                &&
                snsm_activate_ind->comp_params.dcomp == NAS_HCOMP_NEITHER_DIRECT)
          #else
            if ((snsm_activate_ind->hcomp == SNSM_COMP_NEITHER_DIRECT 
                ||
                sndcp_data->vj_count >= SNDCP_MAX_VJ_COUNT) 
                &&
                snsm_activate_ind->dcomp == SNSM_COMP_NEITHER_DIRECT)

          #endif /*#ifdef SNDCP_UPM_INCLUDED*/
#else /* !TI_PS_FF_V42BIS */
         #ifdef SNDCP_UPM_INCLUDED  
            if (snsm_activate_ind->comp_params.hcomp == NAS_HCOMP_OFF
                ||
                sndcp_data->vj_count == SNDCP_MAX_VJ_COUNT) 
          #else
            if (snsm_activate_ind->hcomp == SNSM_COMP_NEITHER_DIRECT
                ||
                sndcp_data->vj_count == SNDCP_MAX_VJ_COUNT) 
          #endif /*#ifdef SNDCP_UPM_INCLUDED*/

#endif /* TI_PS_FF_V42BIS */
            {

              /*
               * No XID negotiation necessary.
               * BUT LLC needs trigger to send LLC XID request to network.
               * If LL_ESTABLISH_REQ or LL_XID_REQ is pending, no LL_XID_REQ
               * is needed here.
               * If LL_RELEASE_REQ is pending, XID must have been negotiated,
               * so it is not necessary.
               */
              USHORT local_sapi_state = MG_IDLE;
              sndcp_get_sapi_state(snsm_activate_ind->sapi,
                                   &local_sapi_state);
           
              if (sndcp_data->always_xid
                  &&
                  (local_sapi_state & MG_EST) == 0
                  &&
                  (local_sapi_state & MG_REL) == 0
                  &&
                  (local_sapi_state & MG_XID) == 0
                 ) {
             
                /*
                 * XID negotiation is not necessary, but done for LLC.
                 */
                /*
                 * Set the N-PDU number in the affected nu instance to 0.
                 */
                sig_mg_nu_reset(snsm_activate_ind->nsapi, TRUE);
                /*
                 * Uplink data transfer on SAPI is completely suspended.
                 */
                sig_mg_su_suspend(snsm_activate_ind->sapi);
                sig_mg_sua_suspend(snsm_activate_ind->sapi);
                mg_suspend_affected_nus(snsm_activate_ind->sapi);
                /*
                 * Send prim.
                 */
                mg_send_empty_xid_req(snsm_activate_ind);

              } else {
                /*
                 * No XID negotiation necessary.
                 */

                /*
                 * LLC may send data now
                 */
                sig_mg_sd_getunitdata(snsm_activate_ind->sapi, snsm_activate_ind->nsapi);
                /*
                 * Open DTI connection.
                 */
#ifndef SNDCP_UPM_INCLUDED
                mg_dti_open(snsm_activate_ind->nsapi);
#else
                nu_unitready_ind_if_nec(snsm_activate_ind->nsapi);
#endif
                /*
                 * Set the N-PDU number in the affected nu instance to 0.
                 */
                sig_mg_nu_reset(snsm_activate_ind->nsapi, FALSE);

                mg_send_snsm_activate_res(snsm_activate_ind->nsapi);
                /*
                 * The response is now sent, state flag can be unset.
                 */
                sndcp_unset_nsapi_state(snsm_activate_ind->nsapi, MG_ACT);

              }

            } else {
          #ifdef SNDCP_UPM_INCLUDED  
              if (snsm_activate_ind->comp_params.hcomp > NAS_HCOMP_OFF) {
             #else
                if (snsm_activate_ind->hcomp > SNSM_COMP_NEITHER_DIRECT) {
             #endif /*#ifdef SNDCP_UPM_INCLUDED*/
                /*
                 * Increment number of requested compressors.
                 */
                sndcp_data->vj_count++;
              }

              /*
               * XID negotiation is necessary.
               */
              /*
               * Set the N-PDU number in the affected nu instance to 0.
               */
              sndcp_get_sapi_state(snsm_activate_ind->sapi, &sapi_state);
              sig_mg_nu_reset(snsm_activate_ind->nsapi, TRUE);

              if (((sapi_state & MG_XID) == 0)
                  &&
                  ((sapi_state & MG_EST) == 0)) {

                  /*
                   * Uplink data transfer on SAPI is completely suspended.
                   */
                  sig_mg_su_suspend(snsm_activate_ind->sapi);
                  sig_mg_sua_suspend(snsm_activate_ind->sapi);
                  mg_suspend_affected_nus(snsm_activate_ind->sapi);
                /*
                 * Send prim.
                 */
                mg_send_xid_req(snsm_activate_ind);
              } else {
                mg_set_new_xid_block(snsm_activate_ind);
                sndcp_set_sapi_state(snsm_activate_ind->sapi, MG_XID_NEC);
              }

            } /* else from if negotiation necessary */
          } /* else from if (b) { */
        } /* if (spec) {  */
        if ( sndcp_data->tcp_flow)
        {
           TRACE_EVENT("sndcp_data.tcp_flow --- DATA FLOW PRIMITIVE ");
           TRACE_EVENT_P1("nsapi value %d", snsm_activate_ind->nsapi);
	         nd_dti_buffer_ready(snsm_activate_ind->nsapi);
        }
      } /* if (used == FALSE) { */
      break;
    default:
      TRACE_ERROR( "SNSM_ACTIVATE_IND unexpected" );
      break;
  }
  if (snsm_activate_ind != NULL) {
    PFREE(snsm_activate_ind);
  }

} /* mg_snsm_activate_ind() */



/*
+------------------------------------------------------------------------------
| Function    : mg_snsm_deactivate_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive SNSM_DEACTIVATE_IND
|
| Parameters  : *snsm_deactivate_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
#ifdef SNDCP_UPM_INCLUDED
GLOBAL void mg_snsm_deactivate_ind ( T_SN_DEACTIVATE_REQ *snsm_deactivate_ind )
#else
GLOBAL void mg_snsm_deactivate_ind ( T_SNSM_DEACTIVATE_IND *snsm_deactivate_ind )
#endif /*#ifdef SNDCP_UPM_INCLUDED*/
{ 
  UBYTE nsapi = 0;
  BOOL nec = FALSE;

  TRACE_FUNCTION( "mg_snsm_deactivate_ind" );
    
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
      for (nsapi = 0; nsapi < SNDCP_NUMBER_OF_NSAPIS; nsapi ++) {
#ifdef SNDCP_UPM_INCLUDED  
        if (snsm_deactivate_ind->nsapi == nsapi) {
#else
        if (snsm_deactivate_ind->nsapi_set & (0x001 << nsapi)) {
#endif
          USHORT sapi_state = 0;
          BOOL ack = FALSE;
          BOOL used = FALSE;
          UBYTE sapi = 0;

          /*
           * Delete information about requested compressors.
           */
          sndcp_reset_xid_block(&sndcp_data->mg.user_xid_block[nsapi]);
          /*
           * If nsapi is not used, send response anyway to avoid block.
           */
          sndcp_is_nsapi_used(nsapi, &used);
          if (!used) {
#ifdef SNDCP_UPM_INCLUDED  
            PALLOC(snsm_deactivate_res, SN_DEACTIVATE_CNF);
            snsm_deactivate_res->nsapi = nsapi;
          #else
            PALLOC(snsm_deactivate_res, SNSM_DEACTIVATE_RES);
            snsm_deactivate_res->nsapi = nsapi;
          #endif /*#ifdef SNDCP_UPM_INCLUDED*/
            /*
             * Set the "state" of the nsapi.
             */
            sndcp_unset_nsapi_state(nsapi, MG_DEACT);


#ifdef SNDCP_UPM_INCLUDED  
            PSEND(hCommUPM, snsm_deactivate_res);
#else /*#ifdef SNDCP_UPM_INCLUDED*/
            PSEND(hCommSM, snsm_deactivate_res);
#endif /*#ifdef SNDCP_UPM_INCLUDED*/
            continue;
          }


          /*
           * Close affected DTI connection.
           */
#ifdef _SNDCP_DTI_2_
          /* FIX
          for entity test TC TC 321 and TC 327 and TC 262a*/
          sndcp_data->nu = & sndcp_data->nu_base[nsapi];
         /* End FIX */
#endif /* _SNDCP_DTI_2_ */
#ifndef SNDCP_UPM_INCLUDED
          mg_dti_close(nsapi);
#else
          /* 
           * This part is required for EDGE to get next line out of if 
           * statement.
           */
          {} 
#endif
          sndcp_set_nsapi_state(nsapi, MG_DEACT);
          sndcp_unset_nsapi_state(nsapi, MG_ACT);

          sndcp_get_nsapi_ack(nsapi, &ack);
          sndcp_get_nsapi_sapi(nsapi, &sapi);
          if (ack) {
            mg_rel_nsapi_nec(nsapi);
          }
          sndcp_get_sapi_state(sapi, &sapi_state);
          mg_delete_npdus(nsapi);
          sndcp_data->nu_base[nsapi].sn_unitready_ind_pending = FALSE;
          sndcp_data->nu_base[nsapi].sn_ready_ind_pending = FALSE;
          /*
           * is compressor deactivation necessary?
           */
          mg_is_rel_comp_nec(nsapi, &nec);

#ifdef SNDCP_UPM_INCLUDED  
          if ((snsm_deactivate_ind->rel_ind == PS_REL_IND_YES)
              &&
              ((sapi_state & (MG_REL + MG_REL_NEC_LOC + MG_REL_NEC_PEER)) == 0)
             ) {
        #else
          if ((snsm_deactivate_ind->rel_ind == REL_IND_YES)
              &&
             ((sapi_state & (MG_REL + MG_REL_NEC_LOC + MG_REL_NEC_PEER)) == 0)
             ) {
        #endif /*#ifdef SNDCP_UPM_INCLUDED*/
            /*
             * Local deactivation. No LL_XID_REQ will be sent (because rel_ind
             * is REL_IND_YES).
             * No release is pending or needed.
             */

#ifdef SNDCP_UPM_INCLUDED  
              PALLOC(snsm_deactivate_res, SN_DEACTIVATE_CNF);
              snsm_deactivate_res->nsapi = nsapi;
            #else
              PALLOC(snsm_deactivate_res, SNSM_DEACTIVATE_RES);
              snsm_deactivate_res->nsapi = nsapi;
            #endif /*#ifdef SNDCP_UPM_INCLUDED*/
            /*
             * Now the NSAPI is not in use anymore:
             */
            sndcp_set_nsapi_used(nsapi, FALSE);
            sndcp_set_nsapi_ack(nsapi, FALSE);
            /*
             * Set the "state" of the nsapi.
             */
            sndcp_unset_nsapi_state(nsapi, MG_DEACT);
            /*
             * Reset xid blocks.
             */
            mg_reset_compressors(nsapi);


          #ifdef SNDCP_UPM_INCLUDED  
            PSEND(hCommUPM, snsm_deactivate_res);
           #else 
            PSEND(hCommSM, snsm_deactivate_res);
           #endif /*#ifdef SNDCP_UPM_INCLUDED*/
            
          } else if ((sapi_state & (MG_REL + MG_REL_NEC_LOC + MG_REL_NEC_PEER)) 
                     == 0
                    ) {

            /*
             * No release is pending.
             * If no compressor has to be released: respond to SM.
             */
            if (nec) {
              /*
               * If xid req is sent, suspend uplink transfer for affected sapi.
               */
              sig_mg_su_suspend(sapi);
              sig_mg_sua_suspend(sapi);
              mg_suspend_affected_nus(sapi);
              /*
               * Negotiate possible deactivation of compressors.
               */
              mg_send_xid_req_del(sapi);

            } else { /* if (nec)  */

              sndcp_get_sapi_state(sapi, &sapi_state);
              if ((sapi_state & MG_XID_NEC) == 0) {
                /*
                 * No compressor negotiated, no release sent.
                 */

          #ifdef SNDCP_UPM_INCLUDED  
                PALLOC(snsm_deactivate_res, SN_DEACTIVATE_CNF);
                snsm_deactivate_res->nsapi = nsapi;
               #else
                PALLOC(snsm_deactivate_res, SNSM_DEACTIVATE_RES);
                snsm_deactivate_res->nsapi = nsapi;
               #endif /*#ifdef SNDCP_UPM_INCLUDED*/


                /*
                 * Now the NSAPI is not in use anymore:
                 */
                sndcp_set_nsapi_used(nsapi, FALSE);
                sndcp_set_nsapi_ack(nsapi, FALSE);
                /*
                 * Set the "state" of the nsapi.
                 */
                sndcp_unset_nsapi_state(nsapi, MG_DEACT);

              
          #ifdef SNDCP_UPM_INCLUDED  
                PSEND(hCommUPM, snsm_deactivate_res);
              #else /*#ifdef SNDCP_UPM_INCLUDED*/
                PSEND(hCommSM, snsm_deactivate_res);
              #endif /*#ifdef SNDCP_UPM_INCLUDED*/

              }
            } /* if (nec)  */
          } else {/* if ((state & (MG_REL + ....)) == 0) */
            /*
             * LL_RELEASE_REQ is pending. After reception of LL_RELEASE_REQ,
             * if XID negotiatio is necessary, LL_XID_REQ will be sent.
             */
            if (nec) {
              sndcp_set_sapi_state(sapi, MG_XID_NEC);
            }
          }
        }
      }
      break;
    default:
      TRACE_ERROR( "SNSM_DEACTIVATE_IND unexpected" );
      break;
  }
  if (snsm_deactivate_ind != NULL) {
    PFREE(snsm_deactivate_ind);
  }


} /* mg_snsm_deactivate_ind() */



/*
+------------------------------------------------------------------------------
| Function    : mg_snsm_sequence_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive SNSM_SEQUENCE_IND
|
| Parameters  : *snsm_sequence_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
#ifdef SNDCP_UPM_INCLUDED
GLOBAL void mg_snsm_sequence_ind ( T_SN_SEQUENCE_REQ *snsm_sequence_ind )
#else
GLOBAL void mg_snsm_sequence_ind ( T_SNSM_SEQUENCE_IND *snsm_sequence_ind )
#endif /*#ifdef SNDCP_UPM_INCLUDED*/
{ 

#ifdef SNDCP_UPM_INCLUDED
  int i = 0;
  U8 nsapi,rec_no,npdu_number;
#endif

  TRACE_FUNCTION( "mg_snsm_sequence_ind" );
    
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
      {
#ifdef SNDCP_UPM_INCLUDED 

      PALLOC(snsm_sequence_res, SN_SEQUENCE_CNF);

      for (i = 0; 
           i < snsm_sequence_ind->c_receive_no_list; 
           i++) {

        nsapi = snsm_sequence_ind->receive_no_list[i].nsapi;
        rec_no = snsm_sequence_ind->receive_no_list[i].receive_no;

        sndcp_unset_nsapi_state(nsapi, MG_SEQ);
        sig_mg_nu_delete_to(nsapi, rec_no);
        npdu_number = sig_mg_nd_get_rec_no(nsapi);
        snsm_sequence_res->receive_no_list[i].nsapi = nsapi;
        snsm_sequence_res->receive_no_list[i].receive_no = npdu_number;
      }
      snsm_sequence_res->c_receive_no_list = i;
      PSEND(hCommUPM, snsm_sequence_res);
#else
      TRACE_EVENT_P1( "SEQ_IND rec_no: %d", snsm_sequence_ind->rec_no);
      sndcp_unset_nsapi_state(snsm_sequence_ind->nsapi, MG_SEQ);
      sig_mg_nu_delete_to(snsm_sequence_ind->nsapi,
                          snsm_sequence_ind->rec_no);
      sig_mg_nd_get_rec_no(snsm_sequence_ind->nsapi);
#endif /*#ifdef SNDCP_UPM_INCLUDED*/
      break;
      }
    default:
      TRACE_ERROR( "SNSM_SEQUENCE_IND unexpected" );
      break;
  }
  if (snsm_sequence_ind != NULL) {
    PFREE (snsm_sequence_ind);
  }

} /* mg_snsm_sequence_ind() */



/*
+------------------------------------------------------------------------------
| Function    : mg_snsm_modify_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive SNSM_MODIFY_IND
|
| Parameters  : *snsm_modify_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
#ifdef SNDCP_UPM_INCLUDED
GLOBAL void mg_snsm_modify_ind ( T_SN_MODIFY_REQ *snsm_modify_ind )
#else
GLOBAL void mg_snsm_modify_ind ( T_SNSM_MODIFY_IND *snsm_modify_ind )
#endif /*#ifdef SNDCP_UPM_INCLUDED*/
{ 
  /*
   * LLC mode specified?
   */
  BOOL spec = FALSE;
  /*
   * LLC mode acknowledged?
   */
  BOOL b = FALSE;
  BOOL nsapi_used = FALSE;
  BOOL old_nsapi_ack = FALSE;
  UBYTE old_sapi = 0;

  TRACE_FUNCTION( "mg_snsm_modify_ind" );
  
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
      /*
       * If no release/establish will be done, SNSM_MODIFY_RES is expected now.
       */
      sndcp_data->mg.mod_expects = MG_MOD_X_READY;
      /*
       * Is NSAPI already used?
       */
      sndcp_is_nsapi_used(snsm_modify_ind->nsapi, &nsapi_used);
      if (! nsapi_used) {
        mg_mod_nsapi_new(snsm_modify_ind);
      }
      /*
       * Is LLC operation mode changing from unack to ack?
       */
      mg_is_ack(snsm_modify_ind->snsm_qos, &spec, &b);
      sndcp_get_nsapi_ack(snsm_modify_ind->nsapi, &old_nsapi_ack);
      if (spec && b && ! old_nsapi_ack) {
        mg_mod_unack_ack(snsm_modify_ind);
      }
      /*
       * Is LLC operation mode changing from ack to unack?
       */
      if (spec && ! b && old_nsapi_ack) {
        mg_mod_ack_unack(snsm_modify_ind);
      }
      /*
       * Is new sapi different from old one?
       */
      sndcp_get_nsapi_sapi(snsm_modify_ind->nsapi, &old_sapi);
      if (old_sapi != snsm_modify_ind->sapi) {
        mg_mod_sapi_diff(snsm_modify_ind);
      }
      /*
       * Add nsapi to waiting_nsapis
       */

        sndcp_data->mg.waiting_nsapis |= (1 << (snsm_modify_ind->nsapi)); 

      /*
       * The following will be done in any case:
       */
      sndcp_set_nsapi_qos(snsm_modify_ind->nsapi, snsm_modify_ind->snsm_qos);
      sndcp_set_nsapi_prio(snsm_modify_ind->nsapi, snsm_modify_ind->radio_prio);

#ifdef REL99 
      sndcp_set_nsapi_pktflowid(snsm_modify_ind->nsapi, 
                                snsm_modify_ind->pkt_flow_id);
#endif /*REL99*/
      /*
       * If no establish/release is expected, send res now.
       */
      mg_mod_res_if_nec();
      break;
    default:
      TRACE_ERROR( "SNSM_MODIFY_IND unexpected" );
      break;
  }
  if (snsm_modify_ind != NULL) {
    PFREE(snsm_modify_ind);
  }

} /* mg_snsm_modify_ind() */


#ifndef SNDCP_UPM_INCLUDED
/*
+------------------------------------------------------------------------------
| Function    : mg_sn_switch_req
+------------------------------------------------------------------------------
| Description : Handles the primitive SN_SWITCH_REQ
|
| Parameters  : *snswitch_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/

GLOBAL void mg_sn_switch_req ( T_SN_SWITCH_REQ *sn_switch_req )
{ 
#ifdef _SNDCP_DTI_2_
  UBYTE* neighbor = NULL;
#endif /* _SNDCP_DTI_2_ */
  TRACE_FUNCTION( "mg_sn_switch_req" );
  
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
      sndcp_set_nsapi_linkid(sn_switch_req->nsapi,
                             sn_switch_req->dti_linkid);
#ifdef _SNDCP_DTI_2_
      sndcp_get_nsapi_neighbor(sn_switch_req->nsapi, &neighbor);
#endif /* _SNDCP_DTI_2_ */
#ifdef _SIMULATION_
      sndcp_set_nsapi_neighbor(sn_switch_req->nsapi,
                               (sn_switch_req->dti_neighbor == 
                                  0xabcdabcd 
                                ?
                                "PPP" 
                                :
                                "NULL"));
#else /*_SIMULATION_ */
      sndcp_set_nsapi_neighbor(sn_switch_req->nsapi,
                               (UBYTE*)sn_switch_req->dti_neighbor);
#endif /* _SIMULATION_ */
      /*
       * Map sn constants to dti constants.
       */
      if (sn_switch_req->dti_direction == SN_HOME) {
        sndcp_set_nsapi_direction(sn_switch_req->nsapi, HOME);
      } else {
        sndcp_set_nsapi_direction(sn_switch_req->nsapi, NEIGHBOR);
      }
#ifdef _SIMULATION_
#ifdef _SNDCP_DTI_2_
/* FIX for entity test TC 1205*/
      sndcp_data->nu = & sndcp_data->nu_base[sn_switch_req->nsapi];
      if ((sndcp_data->nu->connection_is_opened == TRUE) || 
        ((neighbor != NULL) && !(strcmp(neighbor,"NULL"))))
/* End FIX */
#endif /* _SNDCP_DTI_2_ */
#endif /* _SIMULATION_ */
#ifndef SNDCP_UPM_INCLUDED
      mg_dti_close(sn_switch_req->nsapi);
#endif
      sndcp_data->nu->sn_switch_cnf_expected = TRUE;
#ifndef SNDCP_UPM_INCLUDED
      mg_dti_open(sn_switch_req->nsapi);
#endif      

      break;
    default:
      TRACE_ERROR( "SN_SWITCH_REQ unexpected" );
      break;
  }

  PFREE(sn_switch_req);

} /* mg_sn_switch_req() */
#endif /*SNDCP_UPM_INCLUDED*/


#ifdef SNDCP_UPM_INCLUDED
/*
+------------------------------------------------------------------------------
| Function    : mg_sn_dti_req
+------------------------------------------------------------------------------
| Description : Handles the primitive SN_DTI_REQ
|
| Parameters  : *sn_dti_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_sn_dti_req ( T_SN_DTI_REQ *sn_dti_req )
{ 

  UBYTE* neighbor = NULL;

  /*
   * is nsapi already used?
   */
/*  BOOL used = FALSE;*/
  BOOL ack = FALSE;

  TRACE_FUNCTION( "mg_sn_dti_req" );
  
  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
      sndcp_set_nsapi_linkid(sn_dti_req->nsapi,
                             sn_dti_req->dti_linkid);

      TRACE_EVENT_P1("sn_dti_req->nsapi: %d", sn_dti_req->nsapi);

      if (sn_dti_req->dti_conn == NAS_CONNECT_DTI) {

        sndcp_get_nsapi_neighbor(sn_dti_req->nsapi, &neighbor);
        sndcp_data->nsapi = sn_dti_req->nsapi;

#ifdef SNDCP_2to1
       sndcp_set_nsapi_neighbor(sn_dti_req->nsapi,
                                (U8*)sn_dti_req->dti_neighbor.name);
#else /*SNDCP_2to1*/
#ifdef _SIMULATION_
        sndcp_set_nsapi_neighbor(sn_dti_req->nsapi,
                                 (sn_dti_req->dti_neighbor == 
                                    0xabcdabcd 
                                  ?
                                  "PPP" 
                                  :
                                  "NULL"));
#else /*_SIMULATION_ */
        sndcp_set_nsapi_neighbor(sn_dti_req->nsapi,
                                 (U8*)sn_dti_req->dti_neighbor);
#endif /* _SIMULATION_ */
#endif /*SNDCP_2to1*/

        /*
         * Map sn constants to dti constants.
         * The compiler switch is required because the dti_direction  
         * C-Macros have different values in old and new worlds.
         */

#ifdef SNDCP_UPM_INCLUDED
        if (sn_dti_req->dti_direction == NAS_HOME) 
        {
          sndcp_set_nsapi_direction(sn_dti_req->nsapi, DTI_CHANNEL_TO_LOWER_LAYER);
        } 
        else 
        {
          sndcp_set_nsapi_direction(sn_dti_req->nsapi, DTI_CHANNEL_TO_HIGHER_LAYER);
        }
#else /*SNDCP_UPM_INCLUDED*/
        if (sn_dti_req->dti_direction == DTI_CHANNEL_TO_LOWER_LAYER) 
        {
          sndcp_set_nsapi_direction(sn_dti_req->nsapi, DTI_CHANNEL_TO_LOWER_LAYER);
        } 
        else 
        {
          sndcp_set_nsapi_direction(sn_dti_req->nsapi, DTI_CHANNEL_TO_HIGHER_LAYER);
        }
#endif
        sndcp_set_nsapi_linkid(sn_dti_req->nsapi, 
                               sn_dti_req->dti_linkid);
        if (sn_dti_req->dti_neighbor NEQ (ULONG)TCPIP_NAME)
        {
            mg_dti_open(sn_dti_req->nsapi);
        }
#ifdef SNDCP_UPM_INCLUDED
        sndcp_get_nsapi_ack(sn_dti_req->nsapi, &ack);
        if (ack) {
          UBYTE sapi = 0;
          USHORT stat = MG_IDLE;
          sndcp_get_nsapi_sapi(sn_dti_req->nsapi, &sapi);
          sndcp_get_sapi_state(sapi, &stat);
          /*
           * Do not call nu_ready_ind_if_nec() if establish
           * is ongoing.
           */
          if ((stat & MG_EST) == 0) {
            nu_ready_ind_if_nec(sn_dti_req->nsapi);
          }
        } else {
          nu_unitready_ind_if_nec(sn_dti_req->nsapi);
        }
#endif

       } else {  /*  if (sn_dti_req->dti_conn == SNDCP_CONNECT_DTI) */  

        
        /* check if flow control is  received before PDP activation */
        mg_check_unset_nsapi_flow_ctrl_flag (sn_dti_req->nsapi,MG_MOD_X_NONE);

        mg_dti_close(sn_dti_req->nsapi);
      } /*  if (sn_dti_req->dti_conn == SNDCP_CONNECT_DTI) */

      break;
    default:
      TRACE_ERROR( "SN_DTI_REQ unexpected" );
      break;
  }

  PFREE(sn_dti_req);

} /* mg_sn_dti_req() */



#endif /* SNDCP_UPM_INCLUDED */

#ifdef TI_DUAL_MODE
/*
+------------------------------------------------------------------------------
| Function    : mg_get_pending_pdu_req
+------------------------------------------------------------------------------
| Description : Handles the primitive SN_GET_PENDING_PDU_REQ
|
| Parameters  : *sn_get_pending_pdu_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void mg_get_pending_pdu_req (T_SN_GET_PENDING_PDU_REQ 
                                     *sn_get_pending_pdu_req)
{
  U8 nsapi = 0;
  BOOL ack = FALSE, used = FALSE;
  
  TRACE_FUNCTION( "mg_get_pending_pdu_req" );

  switch( GET_STATE( MG ) )
  {
    case MG_DEFAULT:
    {
      PALLOC(sn_get_pending_pdu_cnf, SN_GET_PENDING_PDU_CNF);
#ifdef _SIMULATION_
      PALLOC(sn_test_get_pending_pdu_cnf, SN_TEST_GET_PENDING_PDU_CNF);
#endif
      memset(sn_get_pending_pdu_cnf->ul_pdus,0, sizeof(T_SN_ul_pdus));
      for (nsapi = 0; nsapi < SN_SIZE_NSAPI; nsapi++) {
        sn_get_pending_pdu_cnf->ul_pdus[nsapi].c_desc_list2 = 0;
        sn_get_pending_pdu_cnf->ul_pdus[nsapi].nsapi = 0;
        sn_get_pending_pdu_cnf->ul_pdus[nsapi].dl_sequence_number = 0;
        sndcp_is_nsapi_used(nsapi, &used);
        if (used) {
          sndcp_get_nsapi_ack(nsapi, &ack);
          if (ack) {/*acknowledged context*/
            sn_get_pending_pdu_cnf = 
                mg_get_unsent_unconfirmed_npdus(nsapi, sn_get_pending_pdu_cnf);
            mg_clean_ack_npdu_queues_leave_data(nsapi);
          } else {/*unacknowledged context*/
            mg_clean_unack_npdu_queues_including_data(nsapi);
          }
        }
      }
      sn_get_pending_pdu_cnf->c_ul_pdus=SN_SIZE_NSAPI;
#ifdef _SIMULATION_
      sm_make_test_pending_pdu_cnf(sn_get_pending_pdu_cnf,
                                   sn_test_get_pending_pdu_cnf);
      PSEND(hCommUPM, sn_test_get_pending_pdu_cnf);
#else
      PSEND(hCommUPM, sn_get_pending_pdu_cnf);
#endif
      break;
    }
    default:
      TRACE_ERROR( "SN_GET_PENDING_PDU_REQ unexpected" );
      break;
  }
  if (sn_get_pending_pdu_req != NULL) {
    PFREE (sn_get_pending_pdu_req);
  }
}
#endif /*TI_DUAL_MODE*/