view src/g23m-gprs/sndcp/sndcp_mgp.c @ 268:f2e52cab0a73

abb_inth.c: check all interrupt causes, not just one The original code used if - else if - else if etc constructs, thus the first detected interrupt was the only one handled. However, Iota ITSTATREG is a clear-on-read register, thus if we only handle the first detected interrupt and skip checking the others, then the other interrupts will be lost, if more than one interrupt happened to occur in one ABB interrupt handling cycle - a form of rare race condition. Change the code to check all interrupts that were read in this cycle.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 13 Jun 2021 18:17:53 +0000
parents fa8dc04885d8
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*/