view src/g23m-gprs/llc/llc_up.c @ 662:8cd8fd15a095

SIM speed enhancement re-enabled and made configurable TI's original code supported SIM speed enhancement, but Openmoko had it disabled, and OM's disabling of speed enhancement somehow caused certain SIM cards to start working which didn't work before (OM's bug #666). Because our FC community is much smaller in year 2020 than OM's community was in their day, we are not able to find one of those #666-affected SIMs, thus the real issue they had encountered remains elusive. Thus our solution is to re-enable SIM speed enhancement and simply wait for if and when someone runs into a #666-affected SIM once again. We provide a SIM_allow_speed_enhancement global variable that allows SIM speed enhancement to be enabled or disabled per session, and an /etc/SIM_spenh file in FFS that allows it to enabled or disabled on a non-volatile basis. SIM speed enhancement is now enabled by default.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 24 May 2020 05:02:28 +0000
parents 219afcfc6250
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :   
|  Modul   :  
+----------------------------------------------------------------------------- 
|  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 LLC and implements all 
|             functions to handles the incoming primitives as described in 
|             the SDL-documentation (U-statemachine)
+----------------------------------------------------------------------------- 
*/ 

#ifndef LLC_UP_C
#define LLC_UP_C
#endif

#define ENTITY_LLC

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

#include <string.h>     /* to get memcpy() */

#include "typedefs.h"   /* to get Condat data types */
#include "vsi.h"        /* to get a lot of macros */
#include "macdef.h"
#include "gprs.h"
#include "gsm.h"        /* to get a lot of macros */
#include "cnf_llc.h"    /* to get cnf-definitions */
#include "mon_llc.h"    /* to get mon-definitions */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include "llc.h"        /* to get the global entity definitions */

#include "llc_uf.h"     /* to get local U functions */
#include "llc_ul.h"     /* to get local U labels */
#include "llc_t200s.h"  /* to get signal interface to T200 */
#include "llc_txs.h"    /* to get signal interface to TX */
#include "llc_llmes.h"  /* to get signal interface to LLME */

/*==== CONST ================================================================*/

/*==== LOCAL VARS ===========================================================*/

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

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



/*
+------------------------------------------------------------------------------
| Function    : u_ll_establish_req
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_ESTABLISH_REQ
|
| Parameters  : *ll_establish_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void u_ll_establish_req ( T_LL_ESTABLISH_REQ *ll_establish_req )
{ 
  int bytelen;
  
  TRACE_FUNCTION( "ll_establish_req" );

  SWITCH_LLC (ll_establish_req->sapi);

  TRACE_2_PARA("s:%d xid-len:%d", ll_establish_req->sapi, BYTELEN(ll_establish_req->sdu.l_buf) );

  /*
   * Set TLLI for current transaction.
   */
  llc_data->u->current_tlli = llc_data->tlli_new;

  if (llc_data->u->ll_xid_resp_pending EQ TRUE)
  {
    PFREE (ll_establish_req);
    TRACE_0_INFO( "LL_ESTABLISH_REQ ignored due to LL_XID_IND collision" );
    return;
  }

  switch (GET_STATE(U))
  {
    case U_ADM:
      /*
       * store Layer-3 XID negotiation parameters, free
       * LL_ESTABLISH_REQ, set retransmission counter to 0 
       * and remember to CNF the establishment afterwards
       */

      /*
       * The layer_3 xid is valid any time, even it is a
       * zero lenght sdu. In this case we have to include
       * an empty l3 xid information field.
       */
      llc_data->requested_l3_xid->valid = TRUE;

      bytelen = BYTELEN( ll_establish_req->sdu.l_buf);
      bytelen = (bytelen < LLC_MAX_L3_XID_LEN ) ? bytelen : LLC_MAX_L3_XID_LEN;

      memcpy( llc_data->requested_l3_xid->value,
              &(ll_establish_req->sdu.buf[ll_establish_req->sdu.o_buf >> 3]),
              bytelen );

      llc_data->requested_l3_xid->length = bytelen;

      PFREE (ll_establish_req);

      llc_data->u->retransmission_counter = 0;

      /*
       * Send LL_ESTABLISH_CNF after successful establishment.
       */
      llc_data->u->ind_cnf_establishment  = CNF_ESTABLISHMENT;

      SET_STATE (U, U_LOCAL_ESTABLISHMENT);

      /*
       * send SABM (w/ Layer 3 XID parameters), start T200
       */
      u_send_sabm ();
      break;

    case U_LOCAL_ESTABLISHMENT:
      /*
       * XID Negotiation of layer-3 parameters not supported in 
       * this case.
       */
      PFREE (ll_establish_req);

      /*
       * Send LL_ESTABLISH_CNF after successful establishment.
       */
      llc_data->u->ind_cnf_establishment = CNF_ESTABLISHMENT;
      break;

    case U_ABM:
      /*
       * store Layer-3 XID negotiation parameters, free
       * LL_ESTABLISH_REQ, set retransmission counter to 0 
       * and remember to CNF the establishment afterwards
       */

      /*
       * The layer_3 xid is valid any time, even it is a
       * zero lenght sdu. In this case we have to include
       * an empty l3 xid information field.
       */
      llc_data->requested_l3_xid->valid = TRUE;

      bytelen = BYTELEN( ll_establish_req->sdu.l_buf);
      bytelen = (bytelen < LLC_MAX_L3_XID_LEN ) ? bytelen : LLC_MAX_L3_XID_LEN;

      memcpy( llc_data->requested_l3_xid->value,
              &(ll_establish_req->sdu.buf[ll_establish_req->sdu.o_buf >> 3]),
              bytelen );

      llc_data->requested_l3_xid->length = bytelen;

      PFREE (ll_establish_req);

      llc_data->u->retransmission_counter = 0;

      /*
       * Send LL_ESTABLISH_CNF after successful establishment.
       */
      llc_data->u->ind_cnf_establishment  = CNF_ESTABLISHMENT;

      SET_STATE (U, U_LOCAL_ESTABLISHMENT);

      sig_u_llme_abmrel_ind();

      u_send_llgmm_status_ind (LLGMM_ERRCS_L3_REEST);

      /*
       * send SABM (w/ Layer 3 XID parameters), start T200
       */
      u_send_sabm ();
      break;

    case U_ESTABLISH_RES_PENDING:
    case U_REMOTE_ESTABLISHMENT:
      PFREE (ll_establish_req);
      TRACE_0_INFO( "LL_ESTABLISH_REQ ignored due to collision" );
      break;

    default:
      PFREE (ll_establish_req);
      TRACE_ERROR( "LL_ESTABLISH_REQ unexpected" );
      break;
  }

} /* u_ll_establish_req() */



/*
+------------------------------------------------------------------------------
| Function    : u_ll_establish_res
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_ESTABLISH_RES
|
| Parameters  : *ll_establish_res - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void u_ll_establish_res ( T_LL_ESTABLISH_RES *ll_establish_res )
{ 
  int bytelen;

  TRACE_FUNCTION( "ll_establish_res" );

  SWITCH_LLC (ll_establish_res->sapi);
  
  switch (GET_STATE(U))
  {
    case U_ESTABLISH_RES_PENDING:
    case U_REMOTE_ESTABLISHMENT:
      if (ll_establish_res->xid_valid == TRUE)
      {
        bytelen = BYTELEN( ll_establish_res->sdu.l_buf);
      
        TRACE_2_PARA("s:%d xid-len:%d", ll_establish_res->sapi, bytelen );

        bytelen = (bytelen < LLC_MAX_L3_XID_LEN ) ? bytelen : LLC_MAX_L3_XID_LEN;

        memcpy( llc_data->requested_l3_xid->value,
                &(ll_establish_res->sdu.buf[ll_establish_res->sdu.o_buf >> 3]),
                bytelen );

        llc_data->requested_l3_xid->length = bytelen;
        llc_data->requested_l3_xid->valid  = TRUE;
      }
      else
      {
        TRACE_1_PARA("s:%d", ll_establish_res->sapi );

        llc_data->requested_l3_xid->valid  = FALSE;
      }
 
      PFREE (ll_establish_res);

      if (GET_STATE(U) == U_REMOTE_ESTABLISHMENT) 
      {
        /*
         * Send UA response with F bit set to 1 and if valid XID
         */
        u_send_ua (1, TRUE);      
      }
      
      SET_STATE (U, U_ABM);
      
      sig_u_t200_stop_req();

      /*
       * <R.LLC.ABMEST_I.A.012>
       * vs. <R.LLC.ABMEST_I.A.015>
       */
      sig_u_llme_abmest_ind();
      break;

    default:
      TRACE_1_PARA("s:%d", ll_establish_res->sapi );
      PFREE (ll_establish_res);
      TRACE_ERROR( "LL_ESTABLISH_RES unexpected" );
      break;
  }

} /* u_ll_establish_res() */



/*
+------------------------------------------------------------------------------
| Function    : u_ll_release_req
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_RELEASE_REQ
|
| Parameters  : *ll_release_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void u_ll_release_req ( T_LL_RELEASE_REQ *ll_release_req )
{ 
  TRACE_FUNCTION( "ll_release_req" );

  SWITCH_LLC (ll_release_req->sapi);
  
  TRACE_1_PARA("s:%d", ll_release_req->sapi );

  /*
   * Set TLLI for current transaction.
   */
  llc_data->u->current_tlli = llc_data->tlli_new;
  
  switch (GET_STATE(U))
  {
    case U_TLLI_UNASSIGNED:
    case U_ADM:
      /*
       * We are already released. Send anytime a LL_RELEASE_CNF to 
       * SNDCP to make it more stable.
       */
      {
        PPASS (ll_release_req, ll_release_cnf, LL_RELEASE_CNF);
        TRACE_0_INFO("LL_RELEASE_REQ not necessary");
        TRACE_1_OUT_PARA("s:%d", ll_release_cnf->sapi);
        PSEND (hCommSNDCP, ll_release_cnf);
      }
      break;

    case U_ABM:
      sig_u_llme_abmrel_ind();
      /*
       * No break.
       */ 
    case U_ESTABLISH_RES_PENDING:
      if (ll_release_req->local EQ LL_REL_LOCAL)
      {
        /*
         * Send LL_RELEASE_CNF to SNDCP.
         */
        PPASS (ll_release_req, ll_release_cnf, LL_RELEASE_CNF);
        TRACE_1_OUT_PARA("s:%d", ll_release_cnf->sapi);
        PSEND (hCommSNDCP, ll_release_cnf);
        
        SET_STATE (U, U_ADM);

        sig_u_t200_stop_req();
      }
      else /* LL_REL_NOTLOCAL */
      {
        PFREE (ll_release_req);

        llc_data->u->retransmission_counter = 0;

        SET_STATE (U, U_LOCAL_RELEASE);

        /*
         * Send GRLC_DATA_REQ (DISC), start T200.
         */
        u_send_disc();
      }
      break;

    case U_REMOTE_ESTABLISHMENT:
      /*
       * We are currently waiting for a LL_ESTABLISH_RSP. But
       * because SNDCP want's us to release the connection, we
       * do so and switch back to ADM operation.
       */ 
      SET_STATE (U, U_ADM);

      if (ll_release_req->local NEQ LL_REL_LOCAL)
      {
        /*
         * Send DM response with F bit set to 1
         */
        llc_data->u->retransmission_counter = 0;

        u_send_dm (1);
      }

      sig_u_t200_stop_req();

      {
        PPASS (ll_release_req, ll_release_cnf, LL_RELEASE_CNF);
        TRACE_1_OUT_PARA("s:%d", ll_release_cnf->sapi);
        PSEND (hCommSNDCP, ll_release_cnf);
      }
      break;
     
    case U_LOCAL_ESTABLISHMENT:
      if (ll_release_req->local EQ LL_REL_LOCAL)
      {
        /*
         * Stop all running procedures. The peer will do the same.
         * Send the LL_RELEASE_CNF to SNDCP.
         */
        PPASS (ll_release_req, ll_release_cnf, LL_RELEASE_CNF);
        TRACE_1_OUT_PARA("s:%d", ll_release_cnf->sapi);
        PSEND (hCommSNDCP, ll_release_cnf);

        SET_STATE (U, U_ADM);

        /*
         * NOTE: The peer may have sent an UA or DM before being released
         *       locally itselve. If we get an UA in state ADM we have to
         *       send an status indication to GMM. This seems to be ok (ANS).
         *       If not, we have to wait until T200 timeout, but this is 40s
         *       on SAPI 11 per default. A unexpected DM response will be 
         *       ignored in state ADM and therefore no problem.
         */

        sig_u_t200_stop_req();
      }
      else /* LL_REL_NOTLOCAL */
      {
        /* 
         * We have just sent an SABM to our peer. The release request has to 
         * be stored and handled later:
         *  1. after timeout of T200 don't restart timer and send rel cnf
         *  2. after receive DM send rel cnf
         *  3. after receive of an UA send DISC and after get UA send rel cnf
         */
        llc_data->u->release_requested = TRUE;
        /*
         * Clear flag after sending an release confirmation or indication.
         */

        PFREE (ll_release_req);
        TRACE_0_INFO("Release request stored");
      }
      break;

    case U_LOCAL_RELEASE:        
      /* 
       * release will indicated later 
       */
      TRACE_0_INFO("LL_RELEASE_REQ already received");
      PFREE (ll_release_req);
      break;

    default:
      PFREE (ll_release_req);
      TRACE_ERROR( "LL_RELEASE_REQ unexpected" );
      break;
  }

} /* u_ll_release_req() */



/*
+------------------------------------------------------------------------------
| Function    : u_ll_xid_req
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_XID_REQ
|
| Parameters  : *ll_xid_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void u_ll_xid_req ( T_LL_XID_REQ *ll_xid_req )
{ 
  int bytelen;

  TRACE_FUNCTION( "u_ll_xid_req" );

  SWITCH_LLC (ll_xid_req->sapi);
  
  TRACE_2_PARA("s:%d xid-len:%d", ll_xid_req->sapi, BYTELEN(ll_xid_req->sdu.l_buf) );

  if (llc_data->u->ll_xid_resp_pending EQ TRUE)
  {
    PFREE (ll_xid_req);
    TRACE_0_INFO( "LL_XID_REQ ignored due to LL_XID_IND collision" );
    return;
  }

  switch (GET_STATE(U))
  {
    case U_ABM:
    case U_ADM:
      /*
       * Copy L3-XID parameter to requested_xid
       * and if currently no cmd frame outstanding, 
       * send XID command frame
       */
      bytelen = BYTELEN( ll_xid_req->sdu.l_buf);
      bytelen = (bytelen < LLC_MAX_L3_XID_LEN ) ? bytelen : LLC_MAX_L3_XID_LEN;

      memcpy( llc_data->requested_l3_xid->value,
              &(ll_xid_req->sdu.buf[ll_xid_req->sdu.o_buf >> 3]),
              bytelen );

      llc_data->requested_l3_xid->length = bytelen;
      llc_data->requested_l3_xid->valid  = TRUE;

      PFREE (ll_xid_req);

      if (llc_data->sapi->pbit_outstanding == FALSE)
      {
        /*
         * No frame with pbit set to 1 currently
         * outstanding, send XID comand
         */
        llc_data->u->retransmission_counter = 0;
        u_tag_xid_parameters(MS_COMMAND, FALSE);
        u_send_xid (MS_COMMAND);
      }
      /* SET_STATE (U, SAME_STATE); */
      break;

    case U_ESTABLISH_RES_PENDING:
    case U_REMOTE_ESTABLISHMENT:
      PFREE (ll_xid_req);
      TRACE_0_INFO( "LL_XID_REQ ignored due to collision" );
      break;

    default:
      /*
       * XID only supported in states ADM + ABM
       */
      PFREE (ll_xid_req);
      TRACE_ERROR( "LL_XID_REQ unexpected" );
      break;
  }

} /* u_ll_xid_req() */



/*
+------------------------------------------------------------------------------
| Function    : u_ll_xid_res
+------------------------------------------------------------------------------
| Description : Handles the primitive LL_XID_RES
|
| Parameters  : *ll_xid_res - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void u_ll_xid_res ( T_LL_XID_RES *ll_xid_res )
{ 
  int bytelen;

  TRACE_FUNCTION( "ll_xid_res" );

  SWITCH_LLC (ll_xid_res->sapi);
  
  TRACE_2_PARA("s:%d xid-len:%d", ll_xid_res->sapi, BYTELEN(ll_xid_res->sdu.l_buf) );

  llc_data->u->ll_xid_resp_pending = FALSE;

  switch (GET_STATE(U))
  {
    case U_ABM:
    case U_ADM:
      /*
       * Copy L3-XID parameter to requested_xid
       * and send XID response frame
       */
      bytelen = BYTELEN( ll_xid_res->sdu.l_buf);
      bytelen = (bytelen < LLC_MAX_L3_XID_LEN ) ? bytelen : LLC_MAX_L3_XID_LEN;

      memcpy( llc_data->requested_l3_xid->value,
              &(ll_xid_res->sdu.buf[ll_xid_res->sdu.o_buf >> 3]),
              bytelen );

      llc_data->requested_l3_xid->length = bytelen;
      llc_data->requested_l3_xid->valid  = TRUE;

      PFREE (ll_xid_res);

      u_tag_xid_parameters(MS_RESPONSE, FALSE);
      u_send_xid (MS_RESPONSE);

      /* SET_STATE (U, SAME_STATE); */
      break;
    
    default:
      /*
       * XID only supported in states ADM + ABM
       */
      PFREE (ll_xid_res);
      TRACE_ERROR( "LL_XID_RES unexpected" );
      break;
  }

} /* u_ll_xid_res() */