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