view src/g23m-gprs/sm/sm_memory_handler.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/*----------------------------------------------------------------------------
|  Project :  3G PS
|  Module  :  SM
+-----------------------------------------------------------------------------
|             Copyright 2003 Texas Instruments.
|             All rights reserved. 
| 
|             This file is confidential and a trade secret of Texas 
|             Instruments .
|             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. 
+-----------------------------------------------------------------------------
| Purpose:    Memory allocation function definition for the SM Entity.
|             For design details, see:
|             8010.908 SM Detailed Specification
+---------------------------------------------------------------------------*/

/*==== DECLARATION CONTROL =================================================*/

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

#include "sm.h"
#include "sm_tft.h"

/*==== CONSTS ===============================================================*/

/*==== TYPES ================================================================*/

/*==== LOCALS ===============================================================*/

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

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

/*
+------------------------------------------------------------------------------
| Function    : sm_pfree
+------------------------------------------------------------------------------
| Description : PFREE macro replacement
|
| Parameters  : data                - memory to free
+------------------------------------------------------------------------------
*/
void sm_pfree(/*@only@*/ /*@null@*/ /*@out@*/ void *data)
{
  if (data != NULL)
  {
    vsi_c_pfree((T_VOID_STRUCT **)&data FILE_LINE_MACRO);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_mfree
+------------------------------------------------------------------------------
| Description : Wrapper for MFREE macro
|
| Parameters  : data                - memory to free
+------------------------------------------------------------------------------
*/
static void sm_mfree(/*@only@*/ /*@out@*/ /*@null@*/ void *data)
{
  if (data != NULL) {
    MFREE(data);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_allocate_context_data
+------------------------------------------------------------------------------
| Description : Allocate an instance of SM_CONTEXT_DATA
|
| Parameters  : None
+------------------------------------------------------------------------------
*/
struct T_SM_CONTEXT_DATA *sm_allocate_context_data(void)
{
  struct T_SM_CONTEXT_DATA *context;

  context           = (struct T_SM_CONTEXT_DATA *)
                       M_ALLOC((U32)sizeof(struct T_SM_CONTEXT_DATA));

  return context;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_assign_context_data_to_nsapi
+------------------------------------------------------------------------------
| Description : Assign a non-zero context data structure to an NSAPI index in
|               sm_context_array.
|
| Parameters  : context             - Context data
|               nsapi               - Index at which to insert data
+------------------------------------------------------------------------------
*/
void
sm_assign_context_data_to_nsapi(/*@only@*/struct T_SM_CONTEXT_DATA *context,
                                int /*@alt U8@*/ nsapi)
{
  TRACE_ASSERT(context != NULL);
  TRACE_ASSERT(sm_data.sm_context_array[nsapi - (int)NAS_NSAPI_5] == NULL);

  sm_data.sm_context_array[nsapi - (int)NAS_NSAPI_5] = context;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_get_context_data_from_nsapi
+------------------------------------------------------------------------------
| Description : Returns a context data structure for the given NSAPI index.
|               Returns NULL, if the context is inactive.
|
| Parameters  : nsapi               - Index at which to fetch data
+------------------------------------------------------------------------------
*/
struct T_SM_CONTEXT_DATA *
sm_get_context_data_from_nsapi(int /*@alt U8@*/ nsapi)
{
  TRACE_ASSERT((T_NAS_nsapi)nsapi >= NAS_NSAPI_5 && nsapi <= NAS_NSAPI_15);

  /*lint -e{661} sm_context_array causes out of bounds access, it does not! */
  return sm_data.sm_context_array[nsapi - (int)NAS_NSAPI_5];
}

/*
+------------------------------------------------------------------------------
| Function    : sm_assign_context_data_to_nsapi
+------------------------------------------------------------------------------
| Description : Returns a context data structure for the given TI value.
|               Returns NULL, if the context is inactive.
|
| Parameters  : ti                  - TI value identifying the context
+------------------------------------------------------------------------------
*/
/*@null@*/struct T_SM_CONTEXT_DATA *
sm_get_context_data_from_ti(int /*@alt U8@*/ ti)
{
  int                       index;

  /* First, search sm_context_array: */
  for (index = 0; index < SM_MAX_NSAPI_OFFSET; index++) {
    if (sm_data.sm_context_array[index] != NULL &&
        (sm_data.sm_context_array[index]->ti & SM_TI_MASK) == (ti & SM_TI_MASK))
    {
      return sm_data.sm_context_array[index];
    }
  }

  /* Next, try in sm_pending_mt_array: */
  for (index = 0; index < SM_MAX_NSAPI_OFFSET; index++) {
    if (sm_data.sm_pending_mt_array[index] != NULL &&
        sm_data.sm_pending_mt_array[index]->ti == ti)
    {
      return sm_data.sm_pending_mt_array[index];
    }
  }

  /* None found: return NULL */
  return NULL;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_free_context_data
+------------------------------------------------------------------------------
| Description : Free context data memory.  Calls de-initialization functions
|               in state machines.
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_free_context_data(/*@only@*/struct T_SM_CONTEXT_DATA *context)
{
  if (context != NULL) {
    sm_user_plane_control_exit        (context);
    sm_network_control_exit           (context);
    sm_context_deactivate_control_exit(context);
    sm_context_control_exit           (context);

    TRACE_ASSERT(context->apn == NULL);
    TRACE_ASSERT(context->requested_pco == NULL);
    TRACE_ASSERT(context->negotiated_pco == NULL);
    TRACE_ASSERT(context->requested_tft.ptr_tft_pf == NULL);
    TRACE_ASSERT(context->active_tft.ptr_tft_pf == NULL);
    TRACE_ASSERT(context->coded_msg == NULL);

    sm_mfree(context);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_free_context_data_by_nsapi
+------------------------------------------------------------------------------
| Description : Frees context identified by NSAPI. Uses sm_free_context_data()
|
| Parameters  : nsapi               - NSAPI
+------------------------------------------------------------------------------
*/
void sm_free_context_data_by_nsapi(int /*@alt U8@*/ nsapi)
{
  U16 index;
  TRACE_ASSERT((T_NAS_nsapi)nsapi >= NAS_NSAPI_5 && nsapi <= NAS_NSAPI_15);

  index = sm_nsapi_to_index((U16)nsapi);
  sm_free_context_data(sm_data.sm_context_array[index]);
  sm_data.sm_context_array[index] = NULL;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_insert_mt_context_data
+------------------------------------------------------------------------------
| Description : Allocates and inserts context data structure in
|               sm_pending_mt_array.
|
| Parameters  : ti                  - TI value identifying context
+------------------------------------------------------------------------------
*/
/*@observer@*/ /*@null@*/ struct T_SM_CONTEXT_DATA *
sm_insert_mt_context_data(int /*@alt U8@*/ ti)
{
  int                       index, insert_index = -1;
  struct T_SM_CONTEXT_DATA *context;

  for (index = 0; index < SM_MAX_NSAPI_OFFSET; index++) {
    if (insert_index < 0 && sm_data.sm_pending_mt_array[index] == NULL) {
      insert_index = index;
    }
    if (sm_data.sm_pending_mt_array[index] != NULL &&
        sm_data.sm_pending_mt_array[index]->ti == ti) {
      (void)TRACE_EVENT_P1("ERROR: Tried to overwrite MT context data for TI=%d!", ti);
      return sm_data.sm_pending_mt_array[index];
    }
  }

  context = sm_allocate_context_data();

  if (context != NULL && insert_index >= 0) {
    memset(context, 0, sizeof(struct T_SM_CONTEXT_DATA));

    context->ti = (U8)ti;

    sm_data.sm_pending_mt_array[insert_index] = context;
  } else if (insert_index < 0) {
    (void)TRACE_ERROR("ERROR: No free entries in MT context data array!");
  } else {
    (void)TRACE_ERROR("ERROR: Unable to allocate memory for context data array!");
  }

  return context;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_extract_mt_context_data
+------------------------------------------------------------------------------
| Description : Searches sm_pending_mt_array for the input TI.  Returns the
|               address of the data structure found, if any; otherwise NULL.
|               If found, the entry in sm_pending_mt_array is reset to NULL.
|
| Parameters  : ti                  - TI value identifying context
+------------------------------------------------------------------------------
*/
/*@null@*/ /*@only@*/struct T_SM_CONTEXT_DATA *
sm_extract_mt_context_data(int /*@alt U8@*/ ti)
{
  int                       index;

  for (index = 0; index < SM_MAX_NSAPI_OFFSET; index++)
  {
    if (sm_data.sm_pending_mt_array[index] != NULL &&
        sm_data.sm_pending_mt_array[index]->ti == ti)
    {
      struct T_SM_CONTEXT_DATA *context;
      context = sm_data.sm_pending_mt_array[index];
      sm_data.sm_pending_mt_array[index] = NULL;

      return context;
    } /* if */
  } /* for */
  return NULL;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_free_pending_mt_context_by_index
+------------------------------------------------------------------------------
| Description : Frees context in sm_pending_mt_array indentified by index
|
| Parameters  : index               - index in sm_pending_mt_array[]
+------------------------------------------------------------------------------
*/
void sm_free_pending_mt_context_by_index(U16 index)
{
  TRACE_ASSERT(index < (U16)SM_MAX_NSAPI_OFFSET);

  /*lint -e{661} sm_context_array causes out of bounds access, it does not! */
  sm_free_context_data(sm_data.sm_pending_mt_array[index]);
  /*lint -e{661} sm_context_array causes out of bounds access, it does not! */
  sm_data.sm_pending_mt_array[index] = NULL;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_linked_nsapis
+------------------------------------------------------------------------------
| Description : Returns the nsapi_set of secondary contexts linked to this
|               context.
|
| Parameters  : context             - context data
+------------------------------------------------------------------------------
*/
U16 sm_linked_nsapis(U8 ti)
{
  struct T_SM_CONTEXT_DATA *context;
  int                       nsapi;
  U16                       linked_nsapis = 0;
  U8                        linked_ti;

  context = sm_get_context_data_from_ti(ti);

  TRACE_ASSERT(context != NULL);

  if (context EQ NULL)
   return linked_nsapis;
	   
  if (sm_is_secondary(context))
  {
    linked_ti = context->linked_ti;
  } else {
    linked_ti = ti;
  }

  for (nsapi = (int)NAS_NSAPI_5; nsapi < NAS_SIZE_NSAPI; nsapi++)
  {
    context = sm_get_context_data_from_nsapi(nsapi);
    if (context != NULL && context->ti != (U8)ti && context->ti != linked_ti &&
        sm_is_secondary(context) && context->linked_ti == (U8)ti)
    {
      linked_nsapis = sm_add_nsapi_to_nsapi_set(nsapi, linked_nsapis);
    } /* if */
  } /* for */

  return linked_nsapis;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_free_coded_msg
+------------------------------------------------------------------------------
| Description : Stores a coded message in context data.
|               Used for retransmissions (i.e. in case of time-outs, resume
|               after suspension).
|
| Parameters  : context             - context data
|               msg                 - coded message
+------------------------------------------------------------------------------
*/
void sm_allocate_and_copy_coded_msg(struct T_SM_CONTEXT_DATA *context,
                                    U8                        est_cause,
                                    /*@in@*/ T_sdu           *msg)
{
  U32  msg_len;
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_allocate_and_copy_coded_msg");
#endif

  msg_len = (U32)(msg->l_buf >> 3);

  if (context->coded_msg != NULL)
  {
    sm_free_coded_msg(context);
  }

  TRACE_ASSERT(context->coded_msg == NULL);
  /* Allocate space for T_sdu (l_buf and o_buf) + air interface message octets */
  context->coded_msg = (T_sdu *)M_ALLOC(msg_len + (U32)offsetof(T_sdu, buf));

  if (context->coded_msg == NULL)
  {
    return;
  }

  /* coded_msg->o_buf is always 0.  So we store the only external parameter
   * in there (est_cause). */
  context->coded_msg->l_buf = msg->l_buf;
  context->coded_msg->o_buf = (U16)est_cause;
  memcpy(context->coded_msg->buf, &msg->buf[(msg->o_buf >> 3)], (size_t)msg_len);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_free_coded_msg
+------------------------------------------------------------------------------
| Description : Frees the coded message stored for this NSAPI, if any.
|
| Parameters  : context             - context data
+------------------------------------------------------------------------------
*/
void sm_free_coded_msg(struct T_SM_CONTEXT_DATA *context)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_free_coded_msg");
#endif

  if (context->coded_msg != NULL) {
    sm_mfree(context->coded_msg);
  }
  context->coded_msg      = NULL;
}


/*======================================================================
 * Network Control Memory Handler Functions
 *======================================================================*/

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_allocate_and_copy_*_pco
+------------------------------------------------------------------------------
| Description : Allocate and copy requested or negotiated PCO data structure.
|
| Parameters  : context             - context data
|               pco_len             - PCO data length
|               pco                 - PCO data
+------------------------------------------------------------------------------
*/
void sm_nw_allocate_and_copy_requested_pco(/*@special@*/
                                           struct T_SM_CONTEXT_DATA *context,
                                           size_t /*@alt U8,U16@*/   pco_len,
                                           /*@unique@*/ U8          *pco)
{
  TRACE_ASSERT(context->requested_pco == NULL);
  context->requested_pco        = (T_SM_pco *)M_ALLOC((U32)(pco_len + 1));
  TRACE_ASSERT(context->requested_pco != NULL);

  context->requested_pco->c_pco_value = (U8)pco_len;
  memcpy(context->requested_pco->pco_value, pco, (size_t)pco_len);
}

void sm_nw_allocate_and_copy_negotiated_pco(/*@special@*/
                                            struct T_SM_CONTEXT_DATA *context,
                                            size_t /*@alt U8@*/       pco_len,
                                            /*@unique@*/ U8          *pco)
{
  TRACE_ASSERT(context->negotiated_pco == NULL);
  context->negotiated_pco       = (T_SM_pco *)M_ALLOC((U32)(pco_len + 1));
  TRACE_ASSERT(context->negotiated_pco != NULL);

  context->negotiated_pco->c_pco_value = (U8)pco_len;
  memcpy(context->negotiated_pco->pco_value, pco, (size_t)pco_len);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_free_*_pco
+------------------------------------------------------------------------------
| Description : Free requested or negotiated PCO data structure
|
| Parameters  : context             - context data
+------------------------------------------------------------------------------
*/
void
sm_nw_free_requested_pco(/*@special@*/struct T_SM_CONTEXT_DATA *context)
{
  if (context->requested_pco != NULL) {
    sm_mfree(context->requested_pco);
    context->requested_pco      = NULL;
  }
}

void
sm_nw_free_negotiated_pco(/*@special@*/struct T_SM_CONTEXT_DATA *context)
{
  if (context->negotiated_pco != NULL) {
    sm_mfree(context->negotiated_pco);
    context->negotiated_pco     = NULL;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_allocate_and_copy_apn
+------------------------------------------------------------------------------
| Description : Allocate and copy APN data structure.  Inserted into context
|               data structure.
|
| Parameters  : context             - Context data
|               apn                 - APN data structure
+------------------------------------------------------------------------------
*/
void sm_nw_allocate_and_copy_apn(/*@special@*/
                                 struct T_SM_CONTEXT_DATA  *context,
                                 U8 c_apn, /*@unique@*/ U8 *apn)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_nw_allocate_and_copy_apn");
#endif

  TRACE_ASSERT(context->apn == NULL);
  context->apn                  = (T_SMREG_apn *)M_ALLOC((U32)sizeof(T_SMREG_apn));
  TRACE_ASSERT(context->apn != NULL);
  context->apn->c_apn_buf       = c_apn;
  memcpy(context->apn->apn_buf, apn, (size_t)c_apn);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_free_apn
+------------------------------------------------------------------------------
| Description : Free APN data structure
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_nw_free_apn(/*@special@*/ struct T_SM_CONTEXT_DATA *context)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_nw_free_apn");
#endif

  if (context->apn != NULL) {
    sm_mfree(context->apn);
    context->apn                = NULL;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_is_address_and_apn_equal
+------------------------------------------------------------------------------
| Description : Compare requested IP address and APN with incoming ditto
|
| Parameters  : context             - Context data
|               address             - incoming IP address
|               v_apn               - valid flag for APN
|               apn                 - APN value (void if v_apn == FALSE)
+------------------------------------------------------------------------------
*/
BOOL sm_nw_is_address_and_apn_equal(struct T_SM_CONTEXT_DATA *context,
                                    T_NAS_ip                 *context_address,
                                    T_M_SM_address           *msg_address,
                                    U8 v_apn, T_M_SM_apn     *apn)
{
  /* Compare IP address */
  if (context_address->ctrl_ip_address == NAS_is_ip_not_present) {
    return FALSE;
  } else if (msg_address->pdp_type_org == (U8)M_SM_IETF_ORG &&
             context->pdp_type == msg_address->pdp_type_no)
  {
    if (context->pdp_type == (U8)SMREG_PDP_IPV4)
    {
      if (msg_address->c_add_info == (U8)NAS_SIZE_IPv4_ADDR &&
          memcmp(context_address->ip_address.ipv4_addr.a4,
                 msg_address->add_info, (size_t)NAS_SIZE_IPv4_ADDR) == 0)
      {
        /* IP address equal: FALLTHROUGH */
      } else {
        return FALSE;
      }
    } else if (context->pdp_type == (U8)SMREG_PDP_IPV6)
    {
      if (msg_address->c_add_info == (U8)NAS_SIZE_IPv6_ADDR &&
          memcmp(context_address->ip_address.ipv6_addr.a6,
                 msg_address->add_info, (size_t)NAS_SIZE_IPv6_ADDR) == 0)
      {
        /* IP address equal: FALLTHROUGH */
      } else {
        return FALSE;
      }
    } else { /* Bogus pdp_type */
      return FALSE;
    }
  } else {
    return FALSE;
  }

  /* Compare APN */
  if (v_apn == (U8)TRUE) {
    /* Incoming APN present: Requested APN must also be present, and have same length and values */
    if (context->apn != NULL) {
      if (context->apn->c_apn_buf == apn->c_apn_value) {
        if (memcmp(context->apn->apn_buf, apn->apn_value,
                   (size_t)apn->c_apn_value) == 0) {
          return TRUE;
        }
      }
    }
    return FALSE;
  } else {
    /* If incoming APN is absent, equality depends on the presence of a requested APN */
    return (context->apn == NULL);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_allocate_and_copy_requested_tft
+------------------------------------------------------------------------------
| Description : Allocate and copy TFT data structure.  Inserted into context
|               data structure.
|
| Parameters  : context             - Context data
|               tft                 - TFT data structure
+------------------------------------------------------------------------------
*/
void sm_nw_allocate_and_copy_requested_tft(/*@special@*/
                                           struct T_SM_CONTEXT_DATA *context,
                                           /*@in@*/
                                           T_NAS_tft *tft)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_nw_allocate_and_copy_requested_tft");
#endif

  /* Free TFT memory if a TFT was already present but with a different
   * number of elements. */
  if (context->requested_tft.ptr_tft_pf != NULL &&
      context->requested_tft.c_tft_pf != tft->c_tft_pf)
  {
    sm_nw_free_requested_tft(context);
  }

  /* Allocate memory if TFT was not present before, or if it was freed above.*/
  if (context->requested_tft.ptr_tft_pf == NULL)
  {
    context->requested_tft.c_tft_pf   = tft->c_tft_pf;
    context->requested_tft.ptr_tft_pf = (T_NAS_tft_pf *)
      M_ALLOC((U32)sizeof(T_NAS_tft_pf) * (U32)context->requested_tft.c_tft_pf);
    TRACE_ASSERT(context->requested_tft.ptr_tft_pf != NULL);
  }

  memcpy(context->requested_tft.ptr_tft_pf, tft->ptr_tft_pf,
         sizeof(T_NAS_tft_pf) * (size_t)context->requested_tft.c_tft_pf);
  context->requested_tft.tft_precence_mask = sm_tft_precence_mask(tft->ptr_tft_pf, tft->c_tft_pf);
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_allocate_active_tft
+------------------------------------------------------------------------------
| Description : Allocate active TFT data structure.  Inserted into context
|               data structure.
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_nw_allocate_active_tft(/*@special@*/struct T_SM_CONTEXT_DATA *context)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_nw_allocate_active_tft");
#endif

  TRACE_ASSERT (context->active_tft.ptr_tft_pf == NULL);
  context->active_tft.c_tft_pf   = (U8)0;
  context->active_tft.ptr_tft_pf = (T_NAS_tft_pf *)
    M_ALLOC((U32)sizeof(T_NAS_tft_pf) * (U32)NAS_SIZE_TFT_FILTER);
  TRACE_ASSERT(context->active_tft.ptr_tft_pf != NULL);
  context->active_tft.tft_precence_mask = (U8)0;
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_free_requested_tft
+------------------------------------------------------------------------------
| Description : Free TFT data structure
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_nw_free_requested_tft(/*@special@*/struct T_SM_CONTEXT_DATA *context)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_nw_free_requested_tft");
#endif

  if (context->requested_tft.ptr_tft_pf != NULL) {
    sm_mfree(context->requested_tft.ptr_tft_pf);
    context->requested_tft.ptr_tft_pf = NULL;
    context->requested_tft.c_tft_pf   = (U8)0;
    context->requested_tft.tft_precence_mask = (U8)0;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_free_active_tft
+------------------------------------------------------------------------------
| Description : Free TFT data structure
|
| Parameters  : context             - Context data
+------------------------------------------------------------------------------
*/
void sm_nw_free_active_tft(/*@special@*/struct T_SM_CONTEXT_DATA *context)
{
#ifdef DEBUG_VERBOSE
  (void)TRACE_FUNCTION("sm_nw_free_active_tft");
#endif

  if (context->active_tft.ptr_tft_pf != NULL) {
    sm_mfree(context->active_tft.ptr_tft_pf);
    context->active_tft.ptr_tft_pf    = NULL;
    context->active_tft.c_tft_pf      = (U8)0;
    context->active_tft.tft_precence_mask = (U8)0;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_store_requested_address
+------------------------------------------------------------------------------
| Description : Utility function which stores the IP address requested from
|               the network.
|
| Parameters  : context             - context data
|               pdp_type            - PDP type number
|               ctrl_ip_address     - IP address type
|               ip_address          - IP address (void if ctrl_ip_address == NAS_is_ip_not_present)
+------------------------------------------------------------------------------
*/
void sm_nw_store_requested_address(struct T_SM_CONTEXT_DATA *context,
                                   U8 pdp_type,
                                   T_NAS_ctrl_ip_address ctrl_ip_address,
                                   T_NAS_ip_address *ip_address)
{
  context->pdp_type               = pdp_type;
  context->requested_address.ctrl_ip_address = ctrl_ip_address;
  if (ctrl_ip_address != NAS_is_ip_not_present) {
    if (pdp_type == (U8)SMREG_PDP_PPP ||
        (pdp_type == (U8)SMREG_PDP_IPV4 && ctrl_ip_address != NAS_is_ipv4) ||
        (pdp_type == (U8)SMREG_PDP_IPV6 && ctrl_ip_address != NAS_is_ipv6)) {
      (void)TRACE_ERROR("Mismatching pdp_type and ip_address controller field in SMREG_PDP_ACTIVATE_REQ - using union controller!");
    }
    switch (ctrl_ip_address)
    {
    case NAS_is_ipv4:
      context->pdp_type           = (U8)SMREG_PDP_IPV4;
      memcpy(context->requested_address.ip_address.ipv4_addr.a4,
             ip_address->ipv4_addr.a4, (size_t)NAS_SIZE_IPv4_ADDR);
      break;
    case NAS_is_ipv6:
      context->pdp_type           = (U8)SMREG_PDP_IPV6;
      memcpy(context->requested_address.ip_address.ipv6_addr.a6,
             ip_address->ipv6_addr.a6, (size_t)NAS_SIZE_IPv6_ADDR);
      break;
    default:
      break;
    }
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_store_negotiated_address
+------------------------------------------------------------------------------
| Description : Utility function which stores the address received from the
|               network.
|
| Parameters  : context             - context data
|               v_address           - valid flag for address
|               address             - IP address (void if v_address == FALSE)
+------------------------------------------------------------------------------
*/
void sm_nw_store_negotiated_address(struct T_SM_CONTEXT_DATA *context,
                                    T_M_SM_address           *address,
                                    U8                        v_address)
{
  if (v_address == (U8)TRUE && address->pdp_type_org == (U8)M_SM_IETF_ORG) {
    /* Update PDP type from message */
    context->pdp_type = address->pdp_type_no;
    if (address->pdp_type_no == (U8)M_SM_IP4_TYPE) {
      if (address->c_add_info != (U8)NAS_SIZE_IPv4_ADDR) {
        (void)TRACE_EVENT_P1("Warning: IPv4 address has length %d != 4!",
                             (int)address->c_add_info);
      }
      context->negotiated_address.ctrl_ip_address = NAS_is_ipv4;
      memcpy(&context->negotiated_address.ip_address, &address->add_info, (size_t)NAS_SIZE_IPv4_ADDR);
    } else if (address->pdp_type_no == (U8)M_SM_IP6_TYPE) {
      if (address->c_add_info != (U8)NAS_SIZE_IPv6_ADDR) {
        (void)TRACE_EVENT_P1("Warning: IPv6 address has length %d != 16!",
                             (int)address->c_add_info);
      }
      context->negotiated_address.ctrl_ip_address = NAS_is_ipv6;
      memcpy(&context->negotiated_address.ip_address, &address->add_info, (size_t)NAS_SIZE_IPv6_ADDR);
    } else {
      (void)TRACE_EVENT_P1("ERROR: Invalid PDP type %d; address discarded!",
                           address->pdp_type_no);
    }
  } else {
    /* Check for static IP address allocation/request;
     * PDP addr IE is not included in this case [3G 24.008, 9.5.2.1] */
    switch (context->requested_address.ctrl_ip_address)
    {
    case NAS_is_ipv4:
      context->pdp_type           = (U8)SMREG_PDP_IPV4;
      context->negotiated_address.ctrl_ip_address = NAS_is_ipv4;
      memcpy(context->negotiated_address.ip_address.ipv4_addr.a4,
             context->requested_address .ip_address.ipv4_addr.a4,
             (size_t)NAS_SIZE_IPv4_ADDR);
      break;
    case NAS_is_ipv6:
      context->pdp_type           = (U8)SMREG_PDP_IPV6;
      context->negotiated_address.ctrl_ip_address = NAS_is_ipv6;
      memcpy(context->negotiated_address.ip_address.ipv6_addr.a6,
             context->requested_address .ip_address.ipv6_addr.a6,
             (size_t)NAS_SIZE_IPv6_ADDR);
      break;
    default:
    /* PPP or other non-IP address context; i.e. no static address alloc. */
    context->negotiated_address.ctrl_ip_address = NAS_is_ip_not_present;
    }
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_nw_copy_negotiated_address_to_requested
+------------------------------------------------------------------------------
| Description : Utility function which copies the address received from the
|               network to be the requested address.  Used for context
|               reactivations, which must use the negotiated IP address.
|
| Parameters  : context             - context data
+------------------------------------------------------------------------------
*/
void sm_nw_copy_negotiated_address_to_requested(struct T_SM_CONTEXT_DATA *context)
{
  sm_nw_store_requested_address(context, context->pdp_type,
                                context->negotiated_address.ctrl_ip_address,
                                &context->negotiated_address.ip_address);
}
 
/*
+------------------------------------------------------------------------------
| Function    : sm_is_address_changed_with_reactivation
+------------------------------------------------------------------------------
| Description : Utility function which compares the address of the air message
|               and the address already stored in the context. This function 
|               is useful only in PDP REACTIVATION cases. If the addresses 
|               are not equal the function returns false and the pdp context
|               gets deactivated.
|
| Parameters  : context             - context data, air message address
+------------------------------------------------------------------------------
*/
BOOL sm_is_address_changed_with_reactivation(struct T_SM_CONTEXT_DATA *context,
                                             T_M_SM_address           *address,
                                             U8                      v_address)
{
  BOOL result = FALSE; 
  if (sm_is_context_pending_reactivation(context))
  {
    if (v_address == (U8)TRUE && address->pdp_type_org == (U8)M_SM_IETF_ORG) 
    {
      if ( (address->pdp_type_no == (U8)M_SM_IP4_TYPE) && 
           (context->negotiated_address.ctrl_ip_address == NAS_is_ipv4) )
      {
        if (memcmp(&context->negotiated_address.ip_address, 
           &address->add_info, (size_t)NAS_SIZE_IPv4_ADDR) != 0)
        {
          result = TRUE;
        }
      } else if ( (address->pdp_type_no == (U8)M_SM_IP6_TYPE) && 
           (context->negotiated_address.ctrl_ip_address == NAS_is_ipv6) )
       {
         if (memcmp(&context->negotiated_address.ip_address, 
           &address->add_info, (size_t)NAS_SIZE_IPv6_ADDR) != 0)
         {
           result = TRUE;
         }
       }
    }
    /* Clear the pending reactivation flag. We don't need this anymore. */
    sm_set_context_pending_reactivation(context, FALSE);
  } 
  if (result == TRUE) {
    (void)TRACE_EVENT_P1( "PDP address changed with reactivation. Deactivate nsapi %d",
                                                                     context->nsapi );
  }
  return result;
}
/*==== END OF FILE ==========================================================*/