view src/g23m-gprs/sm/sm_memory_handler.c @ 263:b5e8dfd114a7

Switch_ON(): go into charging boot mode on either CHGSTS or CHGPRES If someone were to plug and then unplug a charger into a switched-off phone in an extremely brief "glitch" manner, we should do an automatic power-off on boot in this condition. When we were checking only CHGPRES in Switch_ON(), we would go into Misc boot state instead, which is undesirable. Now if we have a CHGSTS but not CHGPRES condition, we will go into charging boot mode, and FCBM will then do the automatic power-off upon detecting absence of the charger in its periodic polling.
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 14 May 2021 05:50:36 +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 ==========================================================*/