view src/g23m-gprs/sm/sm_mm_output_handler.c @ 478:5e39123540e6

hybrid fw: Openmoko-mimicking AT@BAND command implemented
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 14 Jun 2018 06:04:54 +0000
parents 219afcfc6250
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:    Output functions for primitives from SM to the MM entity.
|             For design details, see:
|             8010.908 SM Detailed Specification
+---------------------------------------------------------------------------*/

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

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

#include "sm.h"
#include "message.h"
#include "ccdapi.h"

#include "sm_mm_output_handler.h"
#include "sm_qos.h"
#include "sm_tft.h"

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

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

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

#define SM_MM_SEND_MSG(c,e,s,M) sm_mm_send_msg(c,e,s,BSIZE_##M##)

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

/*
+------------------------------------------------------------------------------
| Function    :  sm_set_ti_pd
+------------------------------------------------------------------------------
| Description : Prepend TI and PD to an outgoing air interface message
|
| Parameters  : ti, pd
|
+------------------------------------------------------------------------------
*/
static void sm_set_ti_pd(U8 ti, T_MSGBUF *msg)
{
  U8 ti_flag  = ti & SM_TI_FLAG;
  U8 msg_type = msg->buf[msg->o_buf >> 3];

  /* Check for extended ti */
  if ( (ti & SM_TI_MASK) > (U8)SM_MAX_NON_EXT_TI) {  /* TRUE == Extended TI */
    /* Value assigned to variable to shut up Visual C */
    U8 ti_msb = ti_flag | 0x70 | PD_SM;
    U8 ti_lsb = ti & 127 | 0x80; /* TI EXT must be 1 [3G 24.007, 11.2.3.1.3] */

    /* Insert extended ti flag + PD in first octet, and ti value in octet 2 */
    (void)ccd_codeByte(msg->buf, (U16)(msg->o_buf-16), (U16)8, ti_msb);
    (void)ccd_codeByte(msg->buf, (U16)(msg->o_buf-8),  (U16)8, ti_lsb);
    msg->l_buf += 16;
    msg->o_buf -= 16;

    (void)TRACE_EVENT_P8("L3 HDR: 0x%02x [0x%02x] 0x%02x {ti_flag=%d, "
                         "ti=%d, pd=%d, ext_ti=%d, msg_type=0x%02x}",
                         msg->buf[msg->o_buf >> 3],
                         msg->buf[(msg->o_buf >> 3) + 1],
                         msg->buf[(msg->o_buf >> 3) + 2],
                         (ti_flag != (U8)0 ? 1 : 0),
                         ti, PD_SM, ti_lsb, msg_type);
  } else {  /* (ti & SM_TI_MASK) <= SM_MAX_NON_EXT_TI:  Non-extended TI */
    /* Value assigned to variable to shut up Visual C */
    U8 ti_val = ti_flag | ((ti & SM_TI_NON_EXT_MASK) << 4) | PD_SM;

    /* Insert non-extended ti value in msg */
    (void)ccd_codeByte(msg->buf, (USHORT)(msg->o_buf-8), (U16)8, ti_val);
    msg->l_buf += 8;
    msg->o_buf -= 8;

    (void)TRACE_EVENT_P6("L3 HDR: 0x%02x [] 0x%02x {ti_flag=%d, "
                         "ti=%d, pd=%d, msg_type=0x%02x}",
                         msg->buf[msg->o_buf >> 3],
                         msg->buf[(msg->o_buf >> 3) + 1],
                         (ti_flag != (U8)0 ? 1 : 0), ti, PD_SM, msg_type);
 }
}

static U8 sm_mmpm_establish_cause(struct T_SM_CONTEXT_DATA *context)
{
  T_PS_tc traffic_class;

  if (context != NULL) {
    /*
     * Call QoS helper function to extract requested traffic class QoS
     * parameter from the requested QoS parameters for this context/NSAPI.
     */
    traffic_class = (T_PS_tc)sm_qos_get_traffic_class(context);

    switch (traffic_class) {
    case PS_TC_CONV:
      return (U8)MMPM_CAUSE_ESTABL_ORIG_CONVERSATIONAL;
    case PS_TC_STREAM:
      return (U8)MMPM_CAUSE_ESTABL_ORIG_STREAMING;
    case PS_TC_INTER:
      return (U8)MMPM_CAUSE_ESTABL_ORIG_INTERACTIVE;
    case PS_TC_BG:
      return (U8)MMPM_CAUSE_ESTABL_ORIG_BACKGROUND;
    default:
      /* For subscribed QoS, high priority signalling is used by default. */
      return (U8)MMPM_CAUSE_ESTABL_ORIG_HIGH_PRIO_SIGNALLING;
    }
  } else {
    return (U8)MMPM_CAUSE_ESTABL_ORIG_HIGH_PRIO_SIGNALLING;
  }
}

static U8 sm_cause_ps_to_air(T_CAUSE_ps_cause *cause)
{
  switch (cause->ctrl_value) {
  case CAUSE_is_from_nwsm:
    return (U8)cause->value.nwsm_cause;
  default:
    (void)TRACE_ERROR("Causes not from M_SM not supported yet!");
    return (U8)cause->value.nwsm_cause;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : send_mmpm_unitdata_req
+------------------------------------------------------------------------------
| Description : Call CCD to code AIM and send MMPM_UNITDATA_REQ primitive.
|
| Parameters  : ti          - Transaction identifier
|               est_cause   - establish cause (for MM)
|               prim        - Formatted air interface message
+------------------------------------------------------------------------------
*/
static void send_mmpm_unitdata_req(U8 ti, U8 est_cause,
                                   /*@null@*/struct T_SM_CONTEXT_DATA *context,
                                   /*@only@*/ /*@null@*/
                                   T_MMPM_UNITDATA_REQ *prim)
{
  (void)TRACE_FUNCTION("send_mmpm_unitdata_req");

  TRACE_ASSERT (prim != NULL);

  if (prim EQ NULL)
    return;

  /* Originating entity is SM */
  prim->org_entity        = (U8)NAS_ORG_ENTITY_SM;

  /* Add establish cause and PDP context status elements */
  prim->v_establish_cause = (U8)TRUE;
  prim->establish_cause   = est_cause;

  prim->v_nsapi_set       = (U8)TRUE;
  prim->nsapi_set         = sm_get_pdp_context_status();

  if (ccd_codeMsg((U8)CCDENT_SM, (U8)UPLINK, (T_MSGBUF *)&prim->sdu,
                  _decodedMsg, (U8)NOT_PRESENT_8BIT) != (U8)ccdOK) {
    /*
     * Error Handling
     */
    (void)TRACE_ERROR( "Error in outgoing message" ) ;
    sm_pfree(prim);
  } else {
    /*
     * Add TI and PD to air interface message
     * Note: "sm_set_ti_pd" updates SDU length and offset according
     * to TI size (i.e. whether extended TIs are needed)
     */
    sm_set_ti_pd(ti, (T_MSGBUF *)&prim->sdu);

    if (context != NULL) {
      /* Store coded message for retransmission etc. */
      sm_allocate_and_copy_coded_msg(context, est_cause, &prim->sdu);
    }

    /* No sending primitives if SM is suspended or not attached
     * - resume will cause retransmission */
    if (!sm_is_suspended() && sm_is_attached()) {
      (void)PSEND(hCommMM, prim);
    } else {
      (void)TRACE_EVENT( "Primitive NOT sent to GMM. SM is suspended or GPRS not attached" );
      sm_pfree(prim);
    }
  }
}

/*
+------------------------------------------------------------------------------
| Function    : sm_mm_send_msg
+------------------------------------------------------------------------------
| Description : Send message using MM.  Codes message using CCD, stores it
|               for retransmission, and sends it (unless SM is suspended).
|
| Parameters  : context     - Context data
|               est_cause   - establish cause (for MM)
|               msg_bitlen  - Maximum message bit length
+------------------------------------------------------------------------------
*/
static void sm_mm_send_msg(struct T_SM_CONTEXT_DATA *context, U8 est_cause,
                           BOOL store_coded_msg, int msg_bitlen)
{
  (void)TRACE_FUNCTION("sm_mm_send_msg");

  {
    T_MMPM_UNITDATA_REQ *mmpm_unitdata_req;

    mmpm_unitdata_req = (T_MMPM_UNITDATA_REQ *)
      vsi_c_new_sdu(SIZ(T_MMPM_UNITDATA_REQ), MMPM_UNITDATA_REQ,
                    (U16)msg_bitlen, offsetof(T_MMPM_UNITDATA_REQ, sdu), /*lint -e413*/
                    ENCODE_OFFSET  FILE_LINE_MACRO);

    TRACE_ASSERT(mmpm_unitdata_req != NULL);

    send_mmpm_unitdata_req(context->ti, est_cause,
                           (store_coded_msg ? context : NULL),
                           mmpm_unitdata_req);
  }
}

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

/*
+------------------------------------------------------------------------------
| Function    : resend_msg
+------------------------------------------------------------------------------
| Description : Resend previously coded message
|
| Parameters  : ti          - Transaction identifier
|               est_cause   - establish cause (for MM)
+------------------------------------------------------------------------------
*/
void resend_msg(struct T_SM_CONTEXT_DATA *context)
{
  T_sdu  *message = context->coded_msg;

  (void)TRACE_FUNCTION("resend_msg");

  /* Send nothing if SM is suspended or not attached */
  if (sm_is_suspended() || !sm_is_attached())
  {
    return;
  }

  if (message != NULL)
  {
    T_MMPM_UNITDATA_REQ *prim;

    prim = (T_MMPM_UNITDATA_REQ *)
      vsi_c_new_sdu(SIZ(T_MMPM_UNITDATA_REQ), MMPM_UNITDATA_REQ,
                    message->l_buf, offsetof(T_MMPM_UNITDATA_REQ, sdu), /*lint -e413*/
                    ENCODE_OFFSET  FILE_LINE_MACRO);

    TRACE_ASSERT (prim != NULL);

    if (prim EQ NULL)
      return;

    prim->sdu.l_buf = message->l_buf;
    memcpy(&prim->sdu.buf[(prim->sdu.o_buf >> 3)], message->buf,
           (size_t)(message->l_buf >> 3));

    /* Originating entity is SM */
    prim->org_entity        = (U8)NAS_ORG_ENTITY_SM;

    /* Add establish cause and PDP context status elements */
    prim->v_establish_cause = (U8)TRUE;
    prim->establish_cause   = (U8)message->o_buf;

    prim->v_nsapi_set       = (U8)TRUE;
    prim->nsapi_set         = sm_get_pdp_context_status();

    (void)PSEND(hCommMM, prim);
  }
}

/*
+------------------------------------------------------------------------------
| Function    : send_mmpm_pdp_context_status_req
+------------------------------------------------------------------------------
| Description : Allocate, pack and send MMPM_PDP_CONTEXT_STATUS_REQ primitive.
|
| Parameters  : None
+------------------------------------------------------------------------------
*/
void send_mmpm_pdp_context_status_req(void)
{
  (void)TRACE_FUNCTION("send_mmpm_pdp_context_status_req");
  {
    PALLOC(prim, MMPM_PDP_CONTEXT_STATUS_REQ);

    TRACE_ASSERT(prim != NULL);
/*lint -e613 (Possible use of null pointer 'prim' in left argument to operator '->') */
    prim->nsapi_set         = sm_get_pdp_context_status();

    (void)PSEND(hCommMM, prim);
/*lint +e613 (Possible use of null pointer 'prim' in left argument to operator '->') */	
  }
}

/* Air Interface Message formatting functions */
void send_msg_activate_pdp_context_request(struct T_SM_CONTEXT_DATA *context)
{
  int   addr_len;
  MCAST(msg, ACTIVATE_PDP_CONTEXT_REQUEST);

  (void)TRACE_FUNCTION("send_msg_activate_pdp_context_request");

  msg->msg_type        = (U8)ACTIVATE_PDP_CONTEXT_REQUEST;
  msg->nsapi.nsapi_val = context->nsapi;

  msg->llc_sapi.sapi   = (U8)PS_SAPI_3;

  /*
   * Assign air message QoS parameters from SMREG parameters. Release conversion included.
   */
  sm_qos_convert_to_aim(&context->requested_qos,
                        &msg->qos, sm_get_current_nw_release());

  switch (context->pdp_type) {
  case SMREG_PDP_PPP:
    msg->address.pdp_type_org = (U8)M_SM_ETSI_ORG;
    msg->address.pdp_type_no  = (U8)M_SM_PPP_TYPE;
    break;
  case SMREG_PDP_IPV6:
    msg->address.pdp_type_org = (U8)M_SM_IETF_ORG;
    msg->address.pdp_type_no  = (U8)M_SM_IP6_TYPE;
    break;
  case SMREG_PDP_IPV4:
    msg->address.pdp_type_org = (U8)M_SM_IETF_ORG;
    msg->address.pdp_type_no  = (U8)M_SM_IP4_TYPE;
    break;
  case SMREG_PDP_EMPTY:
  default:
    msg->address.pdp_type_org = (U8)M_SM_PDP_MT;
    msg->address.pdp_type_no  = (U8)0;
  }

  switch (context->requested_address.ctrl_ip_address) {
  case NAS_is_ipv4:
    addr_len = NAS_SIZE_IPv4_ADDR;
    break;
  case NAS_is_ipv6:
    addr_len = NAS_SIZE_IPv6_ADDR;
    break;
  case NAS_is_ip_not_present: /* No IP address requested == dynamic IP */
  default:
    addr_len = 0;
    break;
  }
  msg->address.c_add_info = (U8)addr_len;
  memcpy(&msg->address.add_info,
         &context->requested_address.ip_address,
         (size_t)addr_len);

  /*
   * Access Point Name.
   */
  if (context->apn != NULL && context->apn->c_apn_buf > (U8)0) {
    msg->v_apn           = (U8)TRUE;
    msg->apn.c_apn_value = context->apn->c_apn_buf;
    memcpy(msg->apn.apn_value,
           context->apn->apn_buf,
           (size_t)context->apn->c_apn_buf);
  } else {
    msg->v_apn           = (U8)FALSE;
    msg->apn.c_apn_value = (U8)0;
  }

  /*
   * Protocol configuration options.
   */
  if (context->requested_pco != NULL &&
      context->requested_pco->c_pco_value > (U8)0) {
    msg->v_pco           = (U8)TRUE;
    msg->pco.c_pco_value = context->requested_pco->c_pco_value;
    memcpy(msg->pco.pco_value,
           context->requested_pco->pco_value,
           (size_t)context->requested_pco->c_pco_value);
  } else {
    msg->v_pco           = (U8)FALSE;
  }

  SM_MM_SEND_MSG(context, sm_mmpm_establish_cause(context),
                 TRUE, ACTIVATE_PDP_CONTEXT_REQUEST);
}

void send_msg_activate_secondary_pdp_context_request(struct T_SM_CONTEXT_DATA *context)
{
  MCAST(msg, ACTIVATE_SECONDARY_PDP_CONTEXT_REQUEST);

  (void)TRACE_FUNCTION("send_msg_activate_secondary_pdp_context_request");

  msg->msg_type        = (U8)ACTIVATE_SECONDARY_PDP_CONTEXT_REQUEST;
  msg->nsapi.nsapi_val = (U8)context->nsapi;

  msg->llc_sapi.sapi   = (U8)PS_SAPI_3;

  /*
   * Assign air message QoS parameters from SMREG parameters. Release conversion included.
   */
  sm_qos_convert_to_aim(&context->requested_qos,
                        &msg->qos, sm_get_current_nw_release());

  if (context->requested_tft.ptr_tft_pf != NULL)
  {
    msg->v_tft = (U8)TRUE;
    sm_tft_convert_to_aim(context, &msg->tft);
  } else {
    msg->v_tft = (U8)FALSE;
  }

  SM_MM_SEND_MSG(context, sm_mmpm_establish_cause(context),
                 TRUE, ACTIVATE_SECONDARY_PDP_CONTEXT_REQUEST);
}

void send_msg_deactivate_pdp_context_accept(struct T_SM_CONTEXT_DATA *context)
{
  MCAST(msg, DEACTIVATE_PDP_CONTEXT_ACCEPT);

  (void)TRACE_FUNCTION("send_msg_deactivate_pdp_context_accept");

  msg->msg_type        = (U8)DEACTIVATE_PDP_CONTEXT_ACCEPT;

  SM_MM_SEND_MSG(context, (U8)MMPM_CAUSE_ESTABL_ORIG_HIGH_PRIO_SIGNALLING,
                 FALSE, DEACTIVATE_PDP_CONTEXT_ACCEPT);
}

void send_msg_deactivate_pdp_context_request(struct T_SM_CONTEXT_DATA *context, /*@partial@*/T_CAUSE_ps_cause *cause, BOOL tear_down)
{
  MCAST(msg, DEACTIVATE_PDP_CONTEXT_REQUEST);

  (void)TRACE_FUNCTION("send_msg_deactivate_pdp_context_request");

  msg->msg_type        = (U8)DEACTIVATE_PDP_CONTEXT_REQUEST;

  msg->sm_cause.sm_cause_val = sm_cause_ps_to_air(cause);

  if (tear_down) {
    msg->v_tear_down   = (U8)TRUE;
    msg->tear_down.tear_down_flag = (U8)1;
  } else {
    msg->v_tear_down   = (U8)FALSE;
  }

  SM_MM_SEND_MSG(context, (U8)MMPM_CAUSE_ESTABL_ORIG_HIGH_PRIO_SIGNALLING,
                 TRUE, DEACTIVATE_PDP_CONTEXT_REQUEST);
}

void send_msg_modify_pdp_context_accept(struct T_SM_CONTEXT_DATA *context)
{
  MCAST(msg, U_MODIFY_PDP_CONTEXT_ACCEPT);

  (void)TRACE_FUNCTION("send_msg_modify_pdp_context_accept");

  msg->msg_type        = (U8)U_MODIFY_PDP_CONTEXT_ACCEPT;

  SM_MM_SEND_MSG(context, (U8)MMPM_CAUSE_ESTABL_ORIG_HIGH_PRIO_SIGNALLING,
                 FALSE, U_MODIFY_PDP_CONTEXT_ACCEPT);
}

void send_msg_modify_pdp_context_request(struct T_SM_CONTEXT_DATA *context)
{
  MCAST(msg, U_MODIFY_PDP_CONTEXT_REQUEST);

  (void)TRACE_FUNCTION("send_msg_modify_pdp_context_request");

  msg->msg_type        = (U8)U_MODIFY_PDP_CONTEXT_REQUEST;

  if (context->sapi != (U8)PS_SAPI_0) {
    msg->v_llc_sapi    = (U8)TRUE;
    msg->llc_sapi.sapi = (U8)context->sapi;
  } else {
    msg->v_llc_sapi    = (U8)FALSE;
  }

  if (sm_qos_is_requested_qos_present(context)) {
    msg->v_qos         = (U8)TRUE;
    /* Assign air message QoS parameters from SMREG parameters. Release conversion included. */
    sm_qos_convert_to_aim(&context->requested_qos,
                          &msg->qos, sm_get_current_nw_release());
  } else {
    msg->v_qos         = (U8)FALSE;
  }

  if (sm_tft_more_to_modify(context))
  {
    msg->v_tft = (U8)TRUE;
    sm_tft_convert_to_aim(context, &msg->tft);
  } else {
    msg->v_tft = (U8)FALSE;
  }

  SM_MM_SEND_MSG(context, (U8)MMPM_CAUSE_ESTABL_ORIG_HIGH_PRIO_SIGNALLING,
                 TRUE, U_MODIFY_PDP_CONTEXT_REQUEST);
}

void send_msg_request_pdp_context_activation_reject(struct T_SM_CONTEXT_DATA *context, /*@partial@*/T_CAUSE_ps_cause *cause)
{
  MCAST(msg, REQUEST_PDP_CONTEXT_ACTIVATION_REJECT);

  (void)TRACE_FUNCTION("send_msg_request_pdp_context_activation_reject");

  msg->msg_type              = (U8)REQUEST_PDP_CONTEXT_ACTIVATION_REJECT;
  msg->sm_cause.sm_cause_val = (U8)sm_cause_ps_to_air(cause);
  {
    /* This message must ALWAYS have TI flag set, as it is a reply to the network. */
    U8 ti = context->ti | SM_TI_FLAG;
    PALLOC_MSG(mmpm_unitdata_req, MMPM_UNITDATA_REQ, REQUEST_PDP_CONTEXT_ACTIVATION_REJECT);

    send_mmpm_unitdata_req(ti, (U8)MMPM_CAUSE_ESTABL_ORIG_HIGH_PRIO_SIGNALLING,
                           NULL, mmpm_unitdata_req);
  }
}

void send_msg_sm_status(U8 ti, /*@partial@*/T_CAUSE_ps_cause *cause)
{
  MCAST(msg, SM_STATUS);

  (void)TRACE_FUNCTION("send_msg_sm_status");

  msg->msg_type              = (U8)SM_STATUS;
  msg->sm_cause.sm_cause_val = sm_cause_ps_to_air(cause);
  {
    PALLOC_MSG(mmpm_unitdata_req, MMPM_UNITDATA_REQ, SM_STATUS);

    send_mmpm_unitdata_req(ti, (U8)MMPM_CAUSE_ESTABL_ORIG_HIGH_PRIO_SIGNALLING,
                           NULL, mmpm_unitdata_req);
  }
}

/*==== END OF FILE ==========================================================*/