line source
/*
+-----------------------------------------------------------------------------
| Project : GSM-PS
| Modul : DL_STATE
+-----------------------------------------------------------------------------
| 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 defines the state machine of the component DL
| (replaces the old channel dependent implementation)
+-----------------------------------------------------------------------------
*/
#ifndef DL_STATE_C
#define DL_STATE_C
#define ENTITY_DL
#define NEW_REJ_ACK /* Acknowledgement by valid reject frame
* in accordance with 3GPP 04.06, 5.5.3.1
* "On receipt of a valid I frame or supervisory frame"
*/
/*==== INCLUDES ===================================================*/
#include "typedefs.h"
#include <string.h>
#include "vsi.h"
#include "pconst.cdg"
#include "custom.h"
#include "gsm.h"
#include "mon_dl.h"
#include "prim.h"
#include "pei.h"
#include "tok.h"
#include "ccdapi.h"
#include "dl.h"
#include "dl_em.h"
#include "DL_trc.h"
/*==== TYPEDEFS ===================================================*/
typedef struct
{
UBYTE channel;
UBYTE sapi;
UBYTE state;
UBYTE T200_Stop;
UBYTE T200_Start;
UBYTE pf_bit_flag;
UBYTE dl_data_ind;
UBYTE mdl_error_ind;
T_CCH* pcch;
} T_CCH_INTERN;
#define T_CCH_INTERN_INIT {0,0,0,0,0,0,0}
/*==== EXPORT =====================================================*/
/*==== PRIVAT =====================================================*/
static int frame_validation (UBYTE channel_type, UBYTE* frame);
static int downlink_idle (T_CCH_INTERN* pcch_i, UBYTE *frame);
static int downlink_contention_resolution (T_CCH_INTERN* pcch_i, UBYTE *frame);
static int downlink_mfe (T_CCH_INTERN* pcch_i, UBYTE *frame);
static int downlink_timer_recovery (T_CCH_INTERN* pcch_i, UBYTE *frame);
static int downlink_awaiting_release (T_CCH_INTERN* pcch_i, UBYTE *frame);
static void downlink_mfe_information (T_CCH_INTERN* pcch_i, UBYTE *frame);
static void downlink_mfe_supervisory (T_CCH_INTERN* pcch_i, UBYTE *frame);
static void downlink_mfe_sabm (T_CCH_INTERN* pcch_i, UBYTE *frame);
static void downlink_mfe_dm (T_CCH_INTERN* pcch_i, UBYTE *frame);
static void downlink_mfe_tr_unnumbered (T_CCH_INTERN* pcch_i, UBYTE *frame, UBYTE state);
static void downlink_i_frame (T_CCH_INTERN* pcch_i, UBYTE *frame);
static void downlink_tr_supervisory (T_CCH_INTERN* pcch_i, UBYTE *frame);
static void downlink_tr_information (T_CCH_INTERN* pcch_i, UBYTE *frame);
static void invoke_retransmission (T_CCH_INTERN* pcch_i, UBYTE frame_nr);
static void enquiry_response (T_CCH_INTERN* pcch_i, UBYTE *frame);
static void mdl_error_ind (UBYTE cause, UBYTE channel_type, UBYTE sapi);
static void nr_error_recovery (T_CCH_INTERN* pcch_i, UBYTE *frame);
static void concatenate (UBYTE ch_type, UBYTE sapi, UBYTE *frame);
static void free_sending_buffer (UBYTE ch_type, UBYTE sapi);
static void repeat_sabm (UBYTE channel, UBYTE sapi);
static void delayed_release_ind(UBYTE channel);
static int uplink_idle (UBYTE channel, UBYTE sapi);
static int uplink_awaiting_establishment (UBYTE channel, UBYTE sapi, UBYTE no_signalling_mode);
static int uplink_mfe (UBYTE channel, UBYTE sapi, UBYTE no_signalling_mode);
static int uplink_timer_recovery (UBYTE channel, UBYTE sapi, UBYTE no_signalling_mode);
static void T200_expiry (UBYTE channel, UBYTE sapi);
/*==== VARIABLES ==================================================*/
/*Removed the const from the definition,rework for issue 25370*/
static UBYTE l2_empty_frame [25] = {
0x00, 0x00, /* the first two dummy bytes only for SACCH L1 header! */
/* here begins the normal empty frame (SDCCH, FACCH) */
0x01, /* address field: SAPI 0 */
0x03, /* control field: UI frame */
0x01, /* length field: length = 0 */
0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
0x2b, 0x2b, 0x2b, 0x2b, 0x2b };
#if 0
static UBYTE l2_invalid_frame [25] = {
0x00, 0x00, /* the first two dummy bytes only for SACCH L1 header! */
/* here begins the normal empty frame (SDCCH, FACCH) */
0x1D, /* address field: SAPI 7 (unallocated SAPI; no action shall be taken on such frames) */
0x03, /* control field: UI frame */
0x01, /* length field: length = 0 */
0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
0x2b, 0x2b, 0x2b, 0x2b, 0x2b };
static UBYTE l2_invalid_frame_0 [25] = {
0x00, 0x00, /* the first two dummy bytes only for SACCH L1 header! */
/* here begins the normal empty frame (SDCCH, FACCH) */
0x00, /* address field: SAPI 0 */
0x00, /* control field: UI frame */
0x00, /* length field: length = 0 */
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 };
#endif /* 0|1 */
static T_CCH_INTERN cch_i;
#if defined(CHECK_PCCHI)
#define CHECK_PCCH_I() if (check_pcch_i(pcch_i, __LINE__)()return;
#define CHECK_PCCH_Ir() if (check_pcch_i(pcch_i, __LINE__)()return -1;
#else
#define CHECK_PCCH_I()
#define CHECK_PCCH_Ir()
#endif /* CHECK_PCCHI */
/*==== FUNCTIONS ==================================================*/
int dl_downlink (UBYTE error_flag, UBYTE channel_type, UBYTE* frame, ULONG fn)
{
UBYTE channel_state = STATE_INVALID;
UBYTE channel = NOT_PRESENT_8BIT;
UBYTE frame_sapi = PS_SAPI_0; /* to calm lint, will be new set for valid frames */
static UBYTE invalid = 0;
int ret = -2;
int cause;
int l2_offset;
GET_INSTANCE_DATA;
TRACE_EVENT_WIN_P1 ("downlink(): dcch0_ch_type:%s",
CH_TYPE_NAME[dl_data->dcch0_ch_type]);
TRACE_EVENT_WIN_P6 ("DL: DCCH0=%s,%s vr=%u vs=%u va=%u T200=%u",
CH_TYPE_NAME[dl_data->cch[C_DCCH0].ch_type],
STATE_DCCH0_NAME[dl_data->state[C_DCCH0]],
dl_data->cch[C_DCCH0].vr, dl_data->cch[C_DCCH0].vs, dl_data->cch[C_DCCH0].va,
dl_data->cch[C_DCCH0].T200_counter);
TRACE_EVENT_WIN_P6 ("DL: DCCH3=%s,%s vr=%u vs=%u va=%u T200=%u",
CH_TYPE_NAME[dl_data->cch[C_DCCH3].ch_type],
STATE_DCCH3_NAME[dl_data->state[C_DCCH3]],
dl_data->cch[C_DCCH3].vr, dl_data->cch[C_DCCH3].vs, dl_data->cch[C_DCCH3].va,
dl_data->cch[C_DCCH3].T200_counter);
if (channel_type EQ L2_CHANNEL_SACCH)
{
l2_offset = 2; /* with layer 1 header */
}
else
{
l2_offset = 0; /* without layer 1 header */
}
#define RR_SHORT_PD_HANDLING
#if defined(RR_SHORT_PD_HANDLING)
/* Handling of unacknowledged UI frames with format type Bter */
#if defined(RR_SHORT_PD_DETECT_KNOWN_MSG_ONLY) /* detection of known messages only */
cause = 0;
switch (frame[l2_offset])
{
case RR_SHORT_PD_SI10:
case RR_SHORT_PD_MEAS_INFO:
if (channel_type EQ L2_CHANNEL_SACCH)
cause = 1;
break;
case RR_SHORT_PD_NOTI_FACCH:
if ((channel_type EQ L2_CHANNEL_FACCH_F) OR
(channel_type EQ L2_CHANNEL_FACCH_H))
cause = 1;
break;
case RR_SHORT_PD_UPLINK_FREE:
cause = 1;
break;
default:
break;
}
if (cause)
{
drr_dl_short_unitdata_ind (channel_type, error_flag, frame,
&frame[l2_offset],
(channel_type EQ L2_CHANNEL_SACCH) ? DL_N201_SACCH_Bter : DL_N201_DCCH_Bter, fn);
return 0;
}
#else /* detection of all possible messages with short L2 header and format Bter */
TRACE_EVENT_WIN_P4 ("detection of format Bter: %02x&%02x=%02x ?= %02x",
frame[l2_offset], BTER_FORMAT_MASK, GET_BTER_FORMAT (&frame[l2_offset]), SHORT_L2_HEADER_TYPE_1);
if ((GET_BTER_FORMAT (&frame[l2_offset]) EQ SHORT_L2_HEADER_TYPE_1))
{
drr_dl_short_unitdata_ind (channel_type, error_flag, frame,
&frame[l2_offset],
(UBYTE)((channel_type EQ L2_CHANNEL_SACCH) ? DL_N201_SACCH_Bter : DL_N201_DCCH_Bter), fn);
return 0;
}
#endif /* kind of Bter detection */
#endif /* RR_SHORT_PD_HANDLING */
/* check frame */
if (error_flag EQ VALID_BLOCK)
{
frame_sapi = GET_SAPI (frame+l2_offset);
if ((frame_sapi NEQ PS_SAPI_0) AND (frame_sapi NEQ PS_SAPI_3))
{
TRACE_EVENT_WIN_P1 ("downlink() returns -1 (wrong SAPI=%u)", frame_sapi);
return -1;
}
cause = frame_validation (channel_type, frame+l2_offset);
if (cause >= 0)
{
TRACE_FUNCTION ("frame validation failed!");
if (invalid EQ 0)
{
TRACE_ERROR ("invalid frame");
invalid = 1; /* only one message per succession */
}
mdl_error_ind ((UBYTE)cause, channel_type, frame_sapi);
return 0;/* ETSI GSM 04.06 Annex G.2 - G.4 */
}
else
invalid = 0;
#if defined(DL_2TO1) || defined(_SIMULATION_)
/* Handling of unacknowledged UI frames on SACCH with SAPI=0 (not format type Bter) */
if ((channel_type EQ L2_CHANNEL_SACCH) AND
(frame_sapi EQ PS_SAPI_0) AND
(GET_FORMAT_TYPE(frame+l2_offset) EQ U_FORMAT) AND
(GET_U_TYPE(frame+l2_offset) EQ UI_FRAME) )
{
drr_dl_unitdata_ind (error_flag, frame, frame+l2_offset+3,
(UBYTE)(GET_LENGTH_INDICATOR (frame+l2_offset)), fn);
return 0;
}
#endif /* DL_2TO1 || _SIMULATION_ */
}
#if defined(DL_2TO1)
else if (channel_type EQ L2_CHANNEL_SACCH)
{ /*
* Indicate invalid SACCH frame for decrement of radio link timeout counter.
* The invalid frame possible contains invalid headers, use length 0.
*/
drr_dl_unitdata_ind (error_flag, frame, frame+l2_offset+3, 0, fn);
}
#endif /* DL_2TO1 */
if (error_flag NEQ VALID_BLOCK)
{
TRACE_EVENT_WIN ("invalid frame->stop download handling");
return 0; /* no further handling */
}
memset (&cch_i, 0, sizeof (T_CCH_INTERN));
switch (channel_type)
{
case L2_CHANNEL_SDCCH:
if (frame_sapi EQ PS_SAPI_3)
{
channel = C_DCCH3;
break;
}
/*lint -fallthrough*/
case L2_CHANNEL_FACCH_F:
case L2_CHANNEL_FACCH_H:
if (frame_sapi EQ PS_SAPI_0)
channel = C_DCCH0;
break;
case L2_CHANNEL_SACCH:
if (frame_sapi EQ PS_SAPI_3)
{ /* SACCH with SAPI=3 only supported with associated TCH (FACCH) */
if ((dl_data->cch[C_DCCH0].ch_type EQ L2_CHANNEL_FACCH_H) OR
(dl_data->cch[C_DCCH0].ch_type EQ L2_CHANNEL_FACCH_F))
channel = C_DCCH3;
}
else
{
TRACE_EVENT_WIN ("No handling of SACCH with SAPI=0 here!");
/*
* The SACCH with SAPI=0 is handled some lines before for DL_2TO1 and
* simulation. Handling of frames other than UI frames is not supported.
*/
}
break;
default:
break;
}/* endswitch channel_type */
if (channel EQ NOT_PRESENT_8BIT)
{
TRACE_EVENT_WIN ("downlink() returns -3");
return -3;
}
else
{
#if defined(DELAYED_SABM)
/* ignore downlinked frames before delayed SABM was sent */
if ((channel EQ C_DCCH0) AND
(dl_data->dcch0_sabm_flag NEQ NOT_PRESENT_8BIT))
{
DL_OFFLINE_TRACE (TRACE_DL_EVENT, channel, channel_type, "DL:pend.SABM->ignore");
return 0;
}
#endif /* DELAYED_SABM */
cch_i.channel = channel;
cch_i.sapi = frame_sapi;
#if defined(_SIMULATION_)
if (channel_type EQ L2_CHANNEL_SACCH)
{
TRACE_EVENT_WIN_P1 ("SACCH: set SAPI=%u set during downlink", frame_sapi);
}
#endif /* _SIMULATION_ */
cch_i.state = channel_state = dl_data->state[channel];
cch_i.pcch = &dl_data->cch[channel];
/*
* The channel type pcch->ch_type is overwritten as input to the downlink
* sub functions. In case of DCCH0 this is temporary only and the channel
* type have to be re-assigned with the value of dl_data->dcch0_ch_type.
*/
cch_i.pcch->ch_type = channel_type;
if (cch_i.pcch->vtx NEQ EMPTY_CMD)
{ /* save bit for the case of unsolicited frames */
cch_i.pf_bit_flag = cch_i.pcch->f_bit;
}
TRACE_EVENT_WIN_P4 ("downlink() in:%s SAPI=%u st=%u vtx=%s",
CH_TYPE_NAME[channel_type], frame_sapi, channel_state,
VTX_NAME[cch_i.pcch->vtx]);
TRACE_EVENT_WIN_P9 ("vr=%u vs=%u va=%u rc=%u contres=%u reje=%u ackp=%u %c=%u",
cch_i.pcch->vr, cch_i.pcch->vs, cch_i.pcch->va, cch_i.pcch->rc,
cch_i.pcch->contention_resolution, cch_i.pcch->reject_exception,
cch_i.pcch->acknowledge_pending,
cch_i.pcch->time_flag ? 'T' : 't', cch_i.pcch->T200_counter);
}
switch (channel_state)
{
case STATE_DISABLED:
case STATE_IDLE_DL:
ret = downlink_idle (&cch_i, frame+l2_offset);
break;
case STATE_CONTENTION_RESOLUTION:
ret = downlink_contention_resolution (&cch_i, frame+l2_offset);
break;
case STATE_MULTIPLE_FRAME_ESTABLISHED:
ret = downlink_mfe (&cch_i, frame+l2_offset);
break;
case STATE_TIMER_RECOVERY:
ret = downlink_timer_recovery (&cch_i, frame+l2_offset);
break;
case STATE_AWAITING_RELEASE:
ret = downlink_awaiting_release (&cch_i, frame+l2_offset);
break;
}/* endswitch channel_state */
if (channel EQ C_DCCH0)
{ /*
* Reconstruct the temporary overwritten pcch->ch_type with the value
* of dl_data->dcch0_ch_type.
*/
cch_i.pcch->ch_type = dl_data->dcch0_ch_type;
}
TRACE_EVENT_WIN_P5 ("%s SAPI=%u vtx=%s (%s#%u)", CH_TYPE_NAME[cch_i.pcch->ch_type], cch_i.sapi,
VTX_NAME[cch_i.pcch->vtx],
__FILE10__, __LINE__);
if (ret NEQ 0)
{
TRACE_EVENT_WIN_P1 ("downlink() returns %d", ret);
return ret;
}
/* transfer states and flags to dl_data */
dl_data->cch[channel].f_bit_flag = dl_data->cch[channel].f_bit = cch_i.pf_bit_flag;
if (cch_i.T200_Start)
{
dl_data->cch[channel].T200_counter = T200_STOPPED;
dl_data->cch[channel].time_flag = TRUE;
}
else if (cch_i.T200_Stop)
{
dl_data->cch[channel].T200_counter = T200_STOPPED;
dl_data->cch[channel].time_flag = FALSE;
}
if (cch_i.dl_data_ind)
{
com_data_ind(channel_type, frame_sapi, fn);
}
if (channel_state NEQ cch_i.state)
{
set_channel_state (
(UBYTE)((frame_sapi EQ PS_SAPI_0) ? C_DCCH0 : C_DCCH3), cch_i.state);
}
if (cch_i.mdl_error_ind)
{
mdl_error_ind ( cch_i.mdl_error_ind, channel_type, frame_sapi);
}
TRACE_EVENT_WIN_P4 ("downlink() out:%s SAPI=%u st=%u vtx=%s",
CH_TYPE_NAME[channel_type], cch_i.sapi, cch_i.state,
VTX_NAME[cch_i.pcch->vtx]);
TRACE_EVENT_WIN_P9 ("vr=%u vs=%u va=%u rc=%u contres=%u reje=%u ackp=%u %c=%u",
cch_i.pcch->vr, cch_i.pcch->vs, cch_i.pcch->va, cch_i.pcch->rc,
cch_i.pcch->contention_resolution, cch_i.pcch->reject_exception,
cch_i.pcch->acknowledge_pending,
cch_i.pcch->time_flag ? 'T' : 't', cch_i.pcch->T200_counter);
TRACE_EVENT_WIN_P4 ("T200=%s %s %s %s",
cch_i.T200_Start ? "Start" : cch_i.T200_Stop ? "Stop" : "...",
cch_i.pf_bit_flag ? "P/F" : "",
cch_i.dl_data_ind ? "DATA_IND" : "", cch_i.mdl_error_ind ? "ERROR_IND" : "");
TRACE_EVENT_WIN_P1 ("downlink() returns %d", ret);
return ret;
}/* endfunc downlink */
LOCAL int frame_validation (UBYTE channel_type, UBYTE* frame)
{
UBYTE frame_length;
BOOL frame_m_bit;
UBYTE N201;
if (!GET_EA (frame))
return FRAME_NOT_IMPLEMENTED; /* ETSI GSM 04.06 Annex G.2.3 */
if (!GET_EL (frame))
return FRAME_NOT_IMPLEMENTED; /* ETSI GSM 04.06 Annex G.4.1 */
frame_length = GET_LENGTH_INDICATOR (frame);
frame_m_bit = GET_M_BIT (frame);
/* get the maximal number of octets */
switch (channel_type)
{
case L2_CHANNEL_SDCCH:
N201 = N201_SDCCH;
break;
case L2_CHANNEL_SACCH:
N201 = N201_SACCH;
break;
default:/* CH_TYPE_FACCH_FR, L2_CHANNEL_FACCH_H */
N201 = N201_FACCH;
break;
}
switch (GET_FORMAT_TYPE (frame))
{
case I_FORMAT: /* I format */
case I1_FORMAT:
if ((frame_length > N201) OR (frame_length EQ 0))
return I_FRAME_WITH_INCORRECT_LENGTH; /* ETSI GSM 04.06 Annex G.4.2 */
if ((frame_length < N201) AND (frame_m_bit EQ 1))
return I_FRAME_WITH_INCORRECT_USE_OF_M_BIT; /* ETSI GSM 04.06 Annex G.4.2 */
break;
case S_FORMAT: /* S format */
if (frame_length OR frame_m_bit)
return S_FRAME_WITH_INCORRECT_PARAMETERS; /* ETSI GSM 04.06 Annex G.4.3 */
if ((frame[1] & 0x0f) EQ 0x0d)
return FRAME_NOT_IMPLEMENTED; /* ETSI GSM 04.06 Annex G.3.1 */
break;
case U_FORMAT: /* U format */
switch (GET_U_TYPE (frame))
{
case DM_FRAME:
case DISC_FRAME:
if (frame_length OR frame_m_bit)
return U_FRAME_WITH_INCORRECT_PARAMETERS; /* ETSI GSM 04.06 Annex G.4.4 */
break;
case UA_FRAME:
case SABM_FRAME:
case UI_FRAME:
if ((frame_length > N201) OR (frame_m_bit))
return U_FRAME_WITH_INCORRECT_PARAMETERS; /* ETSI GSM 04.06 Annex G.4.5 */
break;
default:
return FRAME_NOT_IMPLEMENTED; /* ETSI GSM 04.06 Annex G.3.2 */
/*break;*/
}/* endswitch U frame_type */
break;
}/* endswitch frame_format */
/*
* ETSI GSM 04.06 Annex G.2.1, G.2.2 will be check in the following functions
*/
return -1; /* frame is valid */
}/* endfunc frame_validation */
static int downlink_idle( T_CCH_INTERN* pcch_i, UBYTE *frame)
{
/*
* According to 3GPP TS 04.05, 5.4.5 Idle state:
* While in the idle state:
* - the receipt of a DISC command shall result in the transmission of a
* DM response with the F bit set to the value of the received P bit;
* - the receipt of an I frame or supervisory frame with the P bit set to "1"
* shall result in the transmission of a DM response with the F bit set to
* "1" (as defined in subclause 5.2.2);
* - the content of any received I frame shall be discarded;
* - on receipt of an SABM command, the procedures defined in subclause 5.4.1
* shall be followed;
* - on receipt of UI commands, the procedures defined in subclause 5.3 shall
* be followed;
* - all other frame types shall be discarded.
*/
T_CCH* pcch;
CHECK_PCCH_Ir();
pcch = pcch_i->pcch;
TRACE_FUNCTION ("downlink_idle()");
switch (GET_FORMAT_TYPE (frame))
{
case S_FORMAT: /* S frame */
if (GET_S_TYPE (frame) NEQ RR_CMD)
break;
/*lint -fallthrough*/
case I_FORMAT: /* I frame */
case I1_FORMAT:
if (GET_P_BIT (frame))
{
pcch->vtx = DM_CMD;
pcch_i->pf_bit_flag = TRUE;
}
break;
case U_FORMAT: /* U frame */
if (GET_CR (frame))
{ /* command */
switch (GET_U_TYPE (frame))
{
case SABM_FRAME:
if (!GET_LENGTH_INDICATOR (frame) AND pcch_i->sapi EQ PS_SAPI_3)
{ /*
* Mobile Terminated Establishment, but only for SAPI=3!
*
* According to 3GPP TS 04.06, 5.4.1 Establishment of multiple frame
* operation, 5.4.1.1 General, Note:
* For SAPI 0 the data link is always established by the MS.
*/
com_restore_queue ( pcch_i->sapi, NULL);
pcch->vtx = UA_CMD;
pcch_i->pf_bit_flag = GET_P_BIT (frame);
pcch->va = 0;
pcch->vr = 0;
pcch->vs = 0;
pcch->rc = 0;
}
break;
case DISC_FRAME:
pcch->vtx = DM_CMD;
pcch_i->pf_bit_flag = GET_P_BIT (frame);
break;
case UI_FRAME:
/* drr_dl_unitdata_ind() was called in the main downlink function */
break;
default:
break;
}
}
break;
default:
break;
}
return 0;
}/* endfunc downlink_idle */
static int downlink_contention_resolution(T_CCH_INTERN* pcch_i, UBYTE *frame)
{
GET_INSTANCE_DATA;
UBYTE frame_type;
UBYTE frame_format;
UBYTE frame_cr;
UBYTE establish_cnf = FALSE;
UBYTE release_ind = FALSE;
UBYTE release_ind_cs = NOT_PRESENT_8BIT;
T_CCH* pcch;
CHECK_PCCH_Ir();
pcch = pcch_i->pcch;
TRACE_FUNCTION ("downlink_contention_resolution()");
frame_format = GET_FORMAT_TYPE (frame);
if (frame_format EQ U_FORMAT)
{ /* U frame */
frame_cr = GET_CR (frame);
frame_type = GET_U_TYPE (frame);
if (frame_cr)
{ /* command */
switch (frame_type)
{
case SABM_FRAME:
if (pcch_i->sapi EQ PS_SAPI_3)
{ /* DCCH3 */
/*
* According to 3GPP TS 04.06, 5.4.6.1:
* SAPI = 3, Collision of unnumbered commands and responses.
* Collision situations (Identical transmitted and received commands)
* shall be resolved in the following way: If the transmitted and
* received unnumbered commands (SABM or DISC) are the same, the data
* link layer entities shall send the UA response at the earliest
* possible opportunity. The indicated state shall be entered after
* receiving the UA response. The data link layer entities shall each
* notify its respective layer 3 entity by means of the appropriate
* confirm primitive, i.e. DL-ESTABLISH-CONFIRM or DL-RELEASE-CONFIRM.
*/
if (!GET_LENGTH_INDICATOR (frame))
{
com_clear_queue (PS_SAPI_3);
/* establish_cnf = TRUE; cnf will be sent at uplink opportunity */
pcch_i->pf_bit_flag = GET_P_BIT (frame);
pcch->vtx = UA_CMD;
pcch->va = 0;
pcch->vr = 0;
pcch->vs = 0;
pcch->rc = 0;
pcch_i->T200_Stop = TRUE;
}
else
{
/* no contention resolution procedure with SAPI=3! */
}
}
else
{/* DCCH0 */
/*
* According to 3GPP TS 04.06, 5.4.1.1 General:
* NOTE: SAPI=0 the data link is always established by the MS!
*
* According to 3GPP TS 04.06, 5.4.1.4 Contention resolution
* establishment procedure:
* All frames other than unnumbered frame formats received for the
* SAPI in use during the establishment procedures shall be ignored.
* The reception of unnumbered frames other than UA is treated as
* specified for the normal establishment case.
* NOTE 4: In fact, there are no foreseen cases in which the network
* will send SABM, DISC or DM, but for sake of completeness
* these occurrences are specified and must be treated.
*/
establish_cnf = TRUE;/* Treated as normal establishment case */
pcch_i->pf_bit_flag = GET_P_BIT (frame);
pcch->vtx = UA_CMD;
pcch->va = 0;
pcch->vr = 0;
pcch->vs = 0;
pcch->rc = 0;
pcch_i->T200_Stop = TRUE;
}
break;
case DISC_FRAME:
{
release_ind = TRUE;
pcch_i->pf_bit_flag = GET_P_BIT (frame);
pcch->vtx = DM_CMD;
}
break;
default:
break;
}/* endswitch command frame_type */
}
else
{ /* response */
switch (frame_type)
{
case DM_FRAME:
/*
* PATCH LE 14.09.99
* Ignore DM(F=0) frames
*/
if (GET_P_BIT (frame))
{
release_ind = TRUE;
}
break;
case UA_FRAME:
if (pcch_i->sapi EQ PS_SAPI_0)
{
if (pcch->contention_resolution)
{
if (com_compare_L3_msg (dl_data->dcch0_queue.switch_buffer, frame))
{
establish_cnf = TRUE;
COM_FREE_QUEUE_BUFFER(&dl_data->dcch0_queue, INDEX_SWITCH_BUFFER);
}
else
{
release_ind = TRUE;
release_ind_cs = CAUSE_DL_INFO_FIELD_MISMATCH;
}
}
else
{
if (!GET_LENGTH_INDICATOR (frame))
{
establish_cnf = TRUE;
}
else
{
release_ind = TRUE;
}
}
}/* endif PS_SAPI_0 */
else if (pcch_i->sapi EQ PS_SAPI_3)
{
if (!GET_LENGTH_INDICATOR (frame) OR (pcch->ch_type EQ L2_CHANNEL_SACCH))
{
establish_cnf = TRUE;
}
else
{
release_ind = TRUE;
}
}/* endif PS_SAPI_3 */
if (establish_cnf AND (pcch_i->sapi EQ PS_SAPI_0))
{
dcch3_enable(pcch->ch_type);
}
break;/* endbreak UA_FRAME */
default:
break;
}/* endswitch response frame_type */
}/* endifelse command/response */
if (establish_cnf)
{
drr_dl_establish_cnf (pcch->ch_type, pcch_i->sapi);
pcch->va = 0;
pcch->vr = 0;
pcch->vs = 0;
pcch_i->T200_Stop = TRUE;
pcch_i->state = STATE_MULTIPLE_FRAME_ESTABLISHED;
}
else if (release_ind)
{
if (pcch_i->sapi EQ PS_SAPI_0)
{
if (pcch->contention_resolution)
{
pcch->contention_resolution = FALSE;
COM_FREE_QUEUE_BUFFER(&dl_data->dcch0_queue, INDEX_SWITCH_BUFFER);
}
}
drr_dl_release_ind (pcch->ch_type, pcch_i->sapi, release_ind_cs, FALSE);
pcch_i->T200_Stop = TRUE;
pcch_i->state = STATE_IDLE_DL;
}
}/* endif frame_format == 3 (only unnumbered frames) */
return 0;
}/* endfunc downlink_contention_resolution */
static int downlink_mfe(T_CCH_INTERN* pcch_i, UBYTE *frame)
{
TRACE_EVENT_WIN ("downlink_mfe()");
switch (GET_FORMAT_TYPE (frame))
{
case I_FORMAT:/* I frame */
case I1_FORMAT:
downlink_mfe_information (pcch_i, frame);
break;
case S_FORMAT: /* S frame */
downlink_mfe_supervisory (pcch_i, frame);
break;
case U_FORMAT: /* U frame */
downlink_mfe_tr_unnumbered (pcch_i, frame,
STATE_MULTIPLE_FRAME_ESTABLISHED);
break;
default:
TRACE_EVENT_WIN ("invalid/unknown frame");
break;
}
return 0;
}/* endfunc downlink_mfe */
static void downlink_mfe_supervisory (T_CCH_INTERN* pcch_i, UBYTE *frame)
{
UBYTE frame_cr;
UBYTE frame_pollbit;
UBYTE frame_nr;
UBYTE frame_type;
T_CCH* pcch;
CHECK_PCCH_I();
pcch = pcch_i->pcch;
TRACE_EVENT_WIN ("downlink_mfe_supervisory()");
frame_type = GET_S_TYPE (frame);
/*
* Ignore RNR frame without notification
* (ETSI GSM 04.06, section 6.
* "Special protocol operation on SAPI=0 and SAPI=3", page 53)
*/
if (frame_type EQ RNR_FRAME)
return;
frame_cr = GET_CR (frame);
frame_pollbit = GET_P_BIT (frame);
frame_nr = GET_RECEIVE_NUMBER (frame);
/* in accordance with CCITT Q.921 figure B.7 (sheet 5 to 7 of 10) */
if (frame_pollbit)
{
if (frame_cr)
{
enquiry_response (pcch_i, frame);
}
else
{
mdl_error_ind (UNSOLICITED_SUPERVISORY_RESPONSE, pcch->ch_type, pcch_i->sapi);/* 3GPP TS 04.06, 5.4.2.2 */
}
}
if (com_check_nr (pcch->va, pcch->vs, frame_nr))
{
/*
* N(R) check is successfull
* in accordance with CCITT Q.921 figure B.7 (sheet 6 and 7 of 10)
*/
switch (frame_type)
{
case RR_FRAME:
if (frame_nr EQ pcch->vs)
{
/* T200 handling under ETSI GSM 04.06 section 5.5.3.1 */
if (((8 + frame_nr - pcch->va ) & 7) > 0 /*frame_nr > pcch->va*/)
pcch_i->T200_Stop = TRUE;
pcch->va = frame_nr;
free_sending_buffer (pcch->ch_type, pcch_i->sapi);
}
else
{
if (frame_nr NEQ pcch->va)
{
pcch->va = frame_nr;
pcch_i->T200_Start = TRUE;
}
}
break;
case REJ_FRAME:
/*
* in accordance with ETSI GSM 04.06; chapter 5.5.4.1 i)
*
* clear existing peer receiver busy condition (not applicable in GSM)
*/
/* reset timer T200 */
pcch_i->T200_Stop = TRUE;
/*
* If REJ command with P bit set to 1,
* transmit an appropiate supervisory response frame with F bit set to 1
*/
if (frame_pollbit AND frame_cr)
enquiry_response (pcch_i, frame);
/* transmit the corresponding I frame asap */
invoke_retransmission (pcch_i, frame_nr);
/*
* set its send state variable V(S) and its acknowledge state
* variable V(A) to the value of the N(R) contained in the REJ frame
* control field
*/
pcch->vs = pcch->va = frame_nr;
/*
* if it was an REJ response frame with the F bit set to 1, notify
* a protocol violation to layer 3 (cause=unsolicited supervisory frame)
*
* fulfilled at the beginning of this function!
*/
break;
case RNR_FRAME:
/*
* Ignore frame without notification
* (ETSI GSM 04.06, section 6.
* "Special protocol operation on SAPI=0 and SAPI=3", page 53)
*/
break;
default:
TRACE_EVENT_WIN ("invalid S frame"); /* GSM 04.06 Annex G.3.1 */
mdl_error_ind (FRAME_NOT_IMPLEMENTED, pcch->ch_type, pcch_i->sapi);
break;
}
}
else
{
nr_error_recovery (pcch_i, frame);
}
}/* endfunc downlink_mfe_supervisory */
static void downlink_mfe_sabm (T_CCH_INTERN* pcch_i, UBYTE *frame)
{
TRACE_EVENT_WIN ("downlink_mfe_sabm()");
if (!GET_LENGTH_INDICATOR (frame))
{
T_CCH* pcch;
CHECK_PCCH_I();
pcch = pcch_i->pcch;
if (pcch_i->sapi EQ PS_SAPI_0)
{
/* SACCH0: only unacknowledge mode available -> ignore SABM */
if (pcch->ch_type EQ L2_CHANNEL_SACCH)
return;
/*
* SDCCH0, FACCH: can not be a normal establishment procedure
* because for SAPI=0 the data link is always established by the MS.
* Therefore only the V state variables and any exception states
* will be reseted.
*/
}
else if (pcch_i->sapi EQ PS_SAPI_3)
{ /*
* SDCCH3, SACCH: normal establishment procedure,
* might be a re-establishment according to GSM 04.06, 5.4.1.2
*/
com_clear_queue (PS_SAPI_3);
}
/* respond with an unnumbered acknowledgement */
pcch->vtx = UA_CMD;
/* with the F bit set to the same value as the P bit */
pcch_i->pf_bit_flag = GET_P_BIT (frame);
/* reset timer T200 */
pcch_i->T200_Stop = TRUE;
/* reset all state variables (internal sequence counter) */
pcch->va = 0;
pcch->vr = 0;
pcch->vs = 0;
/* reset the retransmission counter */
pcch->rc = 0;
/* clear all exception conditions */
pcch->reject_exception = FALSE;
pcch->acknowledge_pending = FALSE;
/* enter the multiple-frame-established state */
pcch_i->state = STATE_MULTIPLE_FRAME_ESTABLISHED;
}
else
{
/*
* frame_length NEQ 0 is only possible in contention resolution establishment
* initiated by mobile!
*/
mdl_error_ind (U_FRAME_WITH_INCORRECT_PARAMETERS, pcch_i->pcch->ch_type, pcch_i->sapi);/* according to GSM 04.06, 5.4.2.1 */
}
}/* endfunc mfe_sabm */
static void downlink_mfe_dm (T_CCH_INTERN* pcch_i, UBYTE *frame)
{
T_CCH* pcch;
CHECK_PCCH_I();
pcch = pcch_i->pcch;
if (!GET_P_BIT (frame))
{ /* release after unsolicited DM response during connection */
/* New! Called now by mdl_error_ind() from caller of this function
* drr_dl_release_ind (dl_data, pcch->ch_type, pcch_i->sapi, NOT_PRESENT_8BIT);
*/
if ((pcch->ch_type EQ L2_CHANNEL_SDCCH) AND (pcch_i->sapi EQ PS_SAPI_3))
{
pcch_i->T200_Stop = TRUE;
com_clear_queue (PS_SAPI_3);
}
}
}/* endfunc mfe_dm */
static void downlink_mfe_tr_unnumbered (T_CCH_INTERN* pcch_i,
UBYTE *frame, UBYTE state)
{
UBYTE frame_type;
T_CCH* pcch;
TRACE_EVENT_WIN ("downlink_mfe_tr_unnumbered()");
CHECK_PCCH_I();
pcch = pcch_i->pcch;
frame_type = GET_U_TYPE (frame);
if (GET_CR (frame))
{ /* command */
switch (frame_type)
{
case SABM_FRAME:
downlink_mfe_sabm (pcch_i, frame);
break;
case UI_FRAME:
/* drr_dl_unitdata_ind() was called in the main downlink function */
break;
case DISC_FRAME:
pcch->vtx = UA_CMD;
pcch_i->T200_Stop = TRUE;
pcch_i->state = STATE_AWAITING_RELEASE;
#if !defined(LATE_LEAVING_DEDICATED)
com_leave_dedicated (pcch->ch_type);
#endif /* LATE_LEAVING_DEDICATED */
if (pcch_i->sapi EQ PS_SAPI_0)
{
dcch3_enable(pcch->ch_type);
}
break;
default:
/* GSM 04.06 Annex G.2.2, G.3.2 */
TRACE_EVENT_WIN_P1 ("invalid command U frame (%02x)", frame_type);
break;
}
}
else
{ /* response */
switch (frame_type)
{
case DM_FRAME:
/* fulfill the actions required by 3GPP TS 4.06 section 5.4.2.2, table 7 */
if (!GET_P_BIT(frame))
{
mdl_error_ind (UNSOLICITED_DM_RESPONSE_ABNORMAL_REL, pcch->ch_type, pcch_i->sapi);
}
else if (state EQ STATE_MULTIPLE_FRAME_ESTABLISHED)
{
mdl_error_ind (UNSOLICITED_DM_RESPONSE, pcch->ch_type, pcch_i->sapi);
}
downlink_mfe_dm (pcch_i, frame);
break;
case UA_FRAME:
mdl_error_ind (UNSOLICITED_UA_RESPONSE, pcch->ch_type, pcch_i->sapi);
break;
default:
/* GSM 04.06 Annex G.2.2, G.3.2 */
TRACE_EVENT_WIN_P1 ("invalid response U frame (%02x)", frame_type);
break;
}
}
}/* endfunc downlink_mfe_unnumbered */
static void downlink_i_frame (T_CCH_INTERN* pcch_i, UBYTE *frame)
{
/*
* in accordance with CCITT Q.921 figure B.7 (sheet 8 of 10)
* in accordance with CCITT Q.921 figure B.8 (sheet 7 of 9)
* according to GSM 04.06 (same as CCITT Q.921!)
*/
UBYTE frame_pollbit;
T_CCH* pcch;
CHECK_PCCH_I();
pcch = pcch_i->pcch;
frame_pollbit = GET_P_BIT (frame);
if (GET_SEND_NUMBER (frame) EQ pcch->vr)
{
pcch->vr++;
pcch->vr &= 7;
pcch->reject_exception = FALSE;
concatenate (pcch->ch_type, pcch_i->sapi, frame);
if (!GET_M_BIT (frame))
pcch_i->dl_data_ind = TRUE;/* send DL-DATA indication */
if (frame_pollbit)
{
pcch_i->pf_bit_flag = TRUE;
pcch->vtx = RR_RSP;
pcch->acknowledge_pending = FALSE;
}
else if (pcch->acknowledge_pending EQ FALSE)
{
#if defined(IFRAME_AS_RR)
pcch->vtx = RR_CMD;
#else
pcch->vtx = RR_RSP;
#endif /* IFRAME_AS_RR */
}
}/* endif ns == vr */
else
{
if (pcch->reject_exception)
{
if (frame_pollbit)
{
pcch_i->pf_bit_flag = TRUE;
/*pcch->vtx = RR_RSP; */
pcch->vtx = REJ_CMD;
pcch->acknowledge_pending = FALSE;
}
}
else
{
pcch->reject_exception = TRUE;
pcch_i->pf_bit_flag = frame_pollbit;
pcch->vtx = REJ_CMD;
pcch->acknowledge_pending = FALSE;
}
if (pcch->vtx EQ REJ_CMD)
{
TRACE_EVENT_WIN_P1 ("->REJ_CMD pf=%u", pcch_i->pf_bit_flag);
}
}/* endelse ns != vr */
}/* endfunc downlink_i_frame */
static void downlink_mfe_information ( T_CCH_INTERN* pcch_i, UBYTE *frame)
{
UBYTE frame_nr;
T_CCH* pcch;
CHECK_PCCH_I();
pcch = pcch_i->pcch;
TRACE_EVENT_WIN ("downlink_mfe_information()");
if (!GET_CR (frame))
{ /* GSM 04.06 Annex G.2.2 */
TRACE_EVENT_WIN ("invalid I response (C=0)");
return;
}
frame_nr = GET_RECEIVE_NUMBER (frame);
/* in accordance with CCITT Q.921 figure B.7 (sheet 8 of 10) */
downlink_i_frame (pcch_i, frame);
/* in accordance with CCITT Q.921 figure B.7 (sheet 9 of 10) */
if (com_check_nr (pcch->va, pcch->vs, frame_nr))
{ /* N(R) check is successfull */
if (frame_nr EQ pcch->vs)
{
/* T200 handling under ETSI GSM 04.06 section 5.5.3.1 */
if (((8 + frame_nr - pcch->va ) & 7) > 0 /*frame_nr > pcch->va*/)
pcch_i->T200_Stop = TRUE;
pcch->va = frame_nr;
free_sending_buffer (pcch->ch_type, pcch_i->sapi);
}
else if (frame_nr NEQ pcch->va)
{
pcch->va = frame_nr;
pcch_i->T200_Start = TRUE;
}
}
else
{
nr_error_recovery (pcch_i, frame);
}/* endifelse com_check_nr */
}/* endfunc downlink_mfe_information */
static int downlink_timer_recovery(T_CCH_INTERN* pcch_i, UBYTE *frame)
{
TRACE_EVENT_WIN ("downlink_timer_recovery()");
switch (GET_FORMAT_TYPE (frame))
{
case I_FORMAT:
case I1_FORMAT: /* I frame */
downlink_tr_information (pcch_i, frame);
break;
case S_FORMAT: /* S frame */
downlink_tr_supervisory (pcch_i, frame);
break;
case U_FORMAT: /* U frame */
downlink_mfe_tr_unnumbered (pcch_i, frame, STATE_TIMER_RECOVERY);
break;
default:
TRACE_EVENT_WIN ("invalid/unknown frame");
break;
}
return 0;
}/* endfunc downlink_tr */
static void downlink_tr_supervisory (T_CCH_INTERN* pcch_i, UBYTE *frame)
{
UBYTE frame_cr;
UBYTE frame_pollbit;
UBYTE frame_nr;
T_CCH* pcch;
CHECK_PCCH_I();
pcch = pcch_i->pcch;
TRACE_EVENT_WIN ("downlink_tr_supervisory()");
frame_cr = GET_CR (frame);
frame_pollbit = GET_P_BIT (frame);
frame_nr = GET_RECEIVE_NUMBER (frame);
switch (GET_S_TYPE (frame))
{
case RR_FRAME:
/*
* in accordance with CCITT Q.921 figure B.8 (sheet 5 and 6 of 9) and
* 3GPP 04.06, 5.5.3.1 "On receipt of a valid I frame or supervisory frame"
* and 5.5.7 "Waiting acknowledgement".
*/
if (frame_pollbit AND frame_cr)
{
enquiry_response (pcch_i, frame);
}
if (com_check_nr (pcch->va, pcch->vs, frame_nr))
{
/* N(R) check is successfull */
TRACE_EVENT_WIN_P5 ("V(A)=%d =< N(R)=%d =< V(S)=%d check is successfull, pf=%u cr=%u",
pcch->va, frame_nr, pcch->vs, frame_pollbit, frame_cr);
pcch->va = frame_nr;
if (frame_pollbit AND !frame_cr)
{ /*
* 3GPP 04.06, 5.5.7:
* The timer recovery state is only cleared if the DL receives a valid
* supervisory frame response with the F bit set to 1.
*/
pcch_i->T200_Stop = TRUE;
pcch_i->state = STATE_MULTIPLE_FRAME_ESTABLISHED;
/* acknowledgement according to GSM 04.06, 5.5.3.1*/
free_sending_buffer (pcch->ch_type, pcch_i->sapi);
}
else
{
invoke_retransmission (pcch_i, frame_nr);
}
}
else
{
nr_error_recovery (pcch_i, frame);
}/* endifelse com_check_nr */
break;
case REJ_FRAME:
#if defined(NEW_REJ_ACK)
/*
* in accordance with
* 3GPP 04.06, 5.5.3.1 "On receipt of a valid I frame or supervisory frame"
*/
if (com_check_nr (pcch->va, pcch->vs, frame_nr))
{
/* N(R) check is successfull */
TRACE_EVENT_WIN_P5 ("V(A)=%d =< N(R)=%d =< V(S)=%d check is successfull, pf=%u cr=%u",
pcch->va, frame_nr, pcch->vs, frame_pollbit, frame_cr);
/* acknowledgement according to GSM 04.06, 5.5.3.1*/
free_sending_buffer (pcch->ch_type, pcch_i->sapi);
pcch->va = frame_nr;
}
#endif /* NEW_REJ_ACK */
/*
* in accordance with GSM 04.06; chapter 5.5.4.1
* Receipt of a valid REJ frame [ii) and iii)]
*
* clear existing peer receiver busy condition (not applicable in GSM)
*/
if (frame_pollbit AND !frame_cr)
{/* REJ response with F bit set to 1 */
/* clear the timer recovery state */
pcch_i->state = STATE_MULTIPLE_FRAME_ESTABLISHED;
/* reset timer T200 */
pcch_i->T200_Stop = TRUE;
#if defined(NEW_REJ_ACK)
/* transmit the corresponding I frame asap */
if (pcch->va NEQ frame_nr)
{
TRACE_EVENT_WIN_P2 ("REJ: V(A)=%d != N(R)=%d => invoke retransmission",
pcch->va, frame_nr);
invoke_retransmission (pcch_i, frame_nr);
}
#else /* NEW_REJ_ACK */
/* transmit the corresponding I frame asap */
invoke_retransmission (pcch_i, frame_nr);
#endif /* NEW_REJ_ACK */
/*
* set its send state variable V(S) and its acknowledge state
* variable V(A) to the value of the N(R) contained in the REJ frame
* control field
*/
pcch->vs = pcch->va = frame_nr;
}
else
{
/*
* set its its acknowledge state variable V(A) to the value
* of the N(R) contained in the REJ frame control field
*/
pcch->va = frame_nr;
/*
* if REJ command with P bit set to 1,
* transmit an appropiate supervisory response frame with F bit set to 1
*/
if (frame_pollbit AND frame_cr)
{
enquiry_response (pcch_i, frame);
}
}
break;
case RNR_FRAME:
/*
* ignore RNR frame without notification
* (ETSI GSM 04.06, section 6.
* "Special protocol operation on SAPI=0 and SAPI=3", page 53)
*/
default:
/* frame not implemented, */
TRACE_EVENT_WIN ("invalid S frame"); /* GSM 04.06 Annex G.3.1 */
return;
}/* endswitch frame_type */
}/* endfunc downlink_tr_supervisory */
static void downlink_tr_information ( T_CCH_INTERN* pcch_i, UBYTE *frame)
{
T_CCH* pcch;
UBYTE frame_nr;
CHECK_PCCH_I();
pcch = pcch_i->pcch;
TRACE_EVENT_WIN ("downlink_tr_information()");
if (!GET_CR (frame))
{ /* GSM 04.06 Annex G.2.2 */
TRACE_EVENT_WIN ("invalid I response (C=0)");
return;
}
/* in accordance with CCITT Q.921 figure B.8 (sheet 7 of 9) */
downlink_i_frame (pcch_i, frame);
/*
* in accordance with CCITT Q.921 figure B.8 (sheet 8 of 9) and
* 3GPP 04.06, 5.5.3.1 "On receipt of a valid I frame or supervisory frame"
* and 5.5.7 "Waiting acknowledgement".
*/
frame_nr = GET_RECEIVE_NUMBER (frame);
if (com_check_nr (pcch->va, pcch->vs, frame_nr))
pcch->va = frame_nr;/* N(R) check is successfull */
else
nr_error_recovery (pcch_i, frame);
}/* endfunc downlink_tr_information */
static int downlink_awaiting_release(T_CCH_INTERN* pcch_i, UBYTE *frame)
{
T_CCH* pcch;
CHECK_PCCH_Ir();
pcch = pcch_i->pcch;
TRACE_FUNCTION ("downlink_awaiting_release()");
if (GET_FORMAT_TYPE (frame) EQ U_FORMAT)
{ /* U frame */
if (GET_CR (frame))
{ /* command */
switch (GET_U_TYPE (frame))
{
case SABM_FRAME:
if (pcch_i->sapi EQ PS_SAPI_0)
{
pcch->vtx = DM_CMD;
pcch_i->pf_bit_flag = GET_P_BIT (frame);
pcch_i->T200_Stop = TRUE;
pcch_i->state = STATE_IDLE_DL;
drr_dl_release_cnf (pcch->ch_type, PS_SAPI_0, FALSE);
}
break;
case UI_FRAME:
/* drr_dl_unitdata_ind() was called in the main downlink function */
break;
case DISC_FRAME:
pcch->vtx = UA_CMD;
pcch_i->T200_Stop = TRUE;
#if !defined(LATE_LEAVING_DEDICATED)
com_leave_dedicated (pcch->ch_type);
#endif /* LATE_LEAVING_DEDICATED */
break;
default:
/* GSM 04.06 Annex G.2.2, G.3.2 */
TRACE_EVENT_WIN_P1 ("invalid command U frame (%02x)", GET_U_TYPE (frame));
break;
}
}
else
{ /* response */
switch (GET_U_TYPE (frame))
{
case DM_FRAME:
/*
* PATCH LE 14.09.99
* Ignore DM(F=0) frames
*/
if (!GET_P_BIT (frame))
break;
/* the same as UA_FRAME */
/*lint -fallthrough*/
case UA_FRAME:
pcch_i->T200_Stop = TRUE;
#if defined(LATE_LEAVING_DEDICATED)
com_leave_dedicated (pcch->ch_type);
#endif /* LATE_LEAVING_DEDICATED */
pcch_i->state = STATE_IDLE_DL;
drr_dl_release_cnf (pcch->ch_type, pcch_i->sapi, TRUE);
break;
default:
TRACE_EVENT_WIN_P1 ("invalid response U frame (%02x)", GET_U_TYPE (frame));
break;
}
}
}
return 0;
}/* endfunc downlink_awaiting_release */
static void invoke_retransmission (T_CCH_INTERN* pcch_i, UBYTE frame_nr)
{
T_CCH* pcch;
CHECK_PCCH_I();
pcch = pcch_i->pcch;
if (pcch->vs NEQ frame_nr)
{ /* decrement V(S) and recover queue for retransmission */
TRACE_EVENT_WIN ("invoke retransmission");
pcch->vs--;
pcch->vs &= 7;
com_recover_queue (pcch_i->sapi);
}
}/* endfunc invoke_retransmission */
static void enquiry_response (T_CCH_INTERN* pcch_i, UBYTE *frame)
{
T_CCH* pcch;
CHECK_PCCH_I();
pcch = pcch_i->pcch;
TRACE_EVENT_WIN ("enquiry_response()");
/*
* in accordance with ETSI GSM 04.06, 5.5.3.2 Receiving supervisory
* commands with the P bit set to "1" and ETSI GSM 04.06, 5.5.4.1 iii
*/
pcch_i->pf_bit_flag = TRUE;
pcch->acknowledge_pending = FALSE;
pcch->vtx = RR_RSP;
}/* endfunc enquiry_response */
#if defined(_SIMULATION_)
LOCAL const char * const _str_error_ind_cause[] =
{
"T200_EXPIRED_N200_PLUS_1_TIMES, \"T200 expired (N200 + 1 times)\"",
"CS_REEST_REQ, \"re-establishment request\"",
"UNSOLICITED_UA_RESPONSE, \"unsolicited UA response\"",
"UNSOLICITED_DM_RESPONSE, \"unsolicited DM response\"",
"UNSOLICITED_DM_RESPONSE_ABNORMAL_REL, \"unsolicited DM response, multiple frame established state\"",
"UNSOLICITED_SUPERVISORY_RESPONSE, \"unsolicited supervisory response\"",
"SEQUENCE_ERROR, \"sequence error\"",
"U_FRAME_WITH_INCORRECT_PARAMETERS, \"U frame with incorrect parameters\"",
"S_FRAME_WITH_INCORRECT_PARAMETERS, \"S frame with incorrect parameters\"",
"I_FRAME_WITH_INCORRECT_USE_OF_M_BIT, \"I frame with incorrect use of M bit\"",
"I_FRAME_WITH_INCORRECT_LENGTH, \"I frame with incorrect length\"",
"FRAME_NOT_IMPLEMENTED, \"frame not implemented\"",
};
#endif /* _SIMULATION_ */
static void mdl_error_ind (UBYTE cause,
UBYTE channel_type, UBYTE sapi)
{
TRACE_EVENT_WIN_P2 ("mdl_error_ind(%u %s)", cause, _str_error_ind_cause[cause]);
switch(cause)
{
case T200_EXPIRED_N200_PLUS_1_TIMES:
case UNSOLICITED_DM_RESPONSE:
case UNSOLICITED_DM_RESPONSE_ABNORMAL_REL:
case SEQUENCE_ERROR:
drr_error_ind (channel_type, sapi);
break;
default:
break;
}
}/* endfunc mdl_error_ind */
static void nr_error_recovery (T_CCH_INTERN* pcch_i, UBYTE *frame)
{
T_CCH* pcch;
CHECK_PCCH_I();
pcch = pcch_i->pcch;
TRACE_EVENT_WIN ("nr_error_recovery()");
DL_OFFLINE_TRACE (TRACE_DL_EVENT, TRACE_CH_UNKNOWN, pcch->ch_type, "N(R) sequence error");
switch (pcch->ch_type)
{
case L2_CHANNEL_SDCCH:
if (pcch_i->sapi EQ PS_SAPI_3)
break;
/*lint -fallthrough*/
case L2_CHANNEL_SACCH:
case L2_CHANNEL_FACCH_F:
case L2_CHANNEL_FACCH_H:
if ((GET_P_BIT (frame) EQ 1) AND !GET_M_BIT (frame))
pcch_i->dl_data_ind = TRUE; /* indicate a complete message to layer 3 */
else
pcch_i->dl_data_ind = FALSE;/* no indication if P bit set to "0" or message is incomplete */
/*
* GSM 04.06, 5.7.4 The data link shall remain in current state
* until it´s release by layer 3 ???
*/
pcch_i->mdl_error_ind = SEQUENCE_ERROR; /* send mdl error ind after sequence error */
DL_EM_CHANNEL_FAILURE;
break;
}
pcch->vtx = EMPTY_CMD;/* no answer after N(R) sequence error */
}/* endfunc nr_error_recovery */
static void concatenate (UBYTE ch_type, UBYTE sapi,UBYTE *frame)
{
GET_INSTANCE_DATA;
switch (ch_type)
{
case L2_CHANNEL_SDCCH:
if (sapi EQ PS_SAPI_0)
com_concatenate (&dl_data->dcch0_in_msg, frame);
else if (sapi EQ PS_SAPI_3)
com_concatenate (&dl_data->dcch3_in_msg, frame);
break;
case L2_CHANNEL_SACCH:
if (sapi EQ PS_SAPI_3)
{
com_concatenate (&dl_data->dcch3_in_msg, frame);
}
break;
case L2_CHANNEL_FACCH_F:
case L2_CHANNEL_FACCH_H:
if (sapi EQ PS_SAPI_0)
{
com_concatenate (&dl_data->dcch0_in_msg, frame);
}
break;
default:
break;
}
}/* endfunc concatenate */
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147) MODULE : DL_COM |
| STATE : code ROUTINE : free_sending_buffer |
+--------------------------------------------------------------------+
PURPOSE : After confirmation of an I frame the sending buffer is
released if it was the last segment. This avoids
resending of I frames after resumption.
*/
static void free_sending_buffer ( UBYTE ch_type, UBYTE sapi)
{
GET_INSTANCE_DATA;
T_QUEUE *queue = NULL;
TRACE_EVENT_WIN_P2 ("free_sending_buffer():%s SAPI=%u", CH_TYPE_NAME[ch_type], sapi);
switch (ch_type)
{
case L2_CHANNEL_SDCCH:
if (sapi EQ PS_SAPI_0)
queue = &dl_data->dcch0_queue;
else if (sapi EQ PS_SAPI_3)
queue = &dl_data->dcch3_queue;
break;
case L2_CHANNEL_SACCH:
if (sapi EQ PS_SAPI_3)
queue = &dl_data->dcch3_queue;
break;
case L2_CHANNEL_FACCH_F:
case L2_CHANNEL_FACCH_H:
if (sapi EQ PS_SAPI_0)
queue = &dl_data->dcch0_queue;
break;
default:
break;
}
if (queue)
{
if (queue->switch_buffer)
{
TRACE_EVENT_WIN_P3 ("CNF on %s SAPI=%u %s (switch_buffer)",
CH_TYPE_NAME[queue->switch_buffer->ch_type],
queue->switch_buffer->sapi,
queue->switch_buffer->cnf ? "CNF required" : "");
com_l3trace (TRACE_UPLINK, queue->switch_buffer->ch_type, (UBYTE *)queue->switch_buffer);
COM_FREE_QUEUE_BUFFER ( queue, INDEX_SWITCH_BUFFER);
}
else if (queue->sending_buffer)
{
TRACE_EVENT_WIN_P4 ("CNF on %s SAPI=%u %s (sending_buffer) act_length=%u",
CH_TYPE_NAME[queue->sending_buffer->ch_type],
queue->sending_buffer->sapi,
queue->sending_buffer->cnf ? "CNF required" : "",
queue->act_length);
if (queue->act_length EQ 0)
{ /* entire message has been sent */
com_l3trace (TRACE_UPLINK, queue->sending_buffer->ch_type, (UBYTE *)queue->sending_buffer);
if (queue->sending_buffer->cnf)
{
drr_dl_data_cnf (sapi);
}
else
{
COM_FREE_QUEUE_BUFFER (queue, INDEX_SENDING_BUFFER);
}
}
}
else
{
TRACE_EVENT_WIN_P2 ("%s SAPI=%u: sending_buffer and switch_buffer=NULL !!!",
CH_TYPE_NAME[ch_type], sapi);
}
}
}/* endfunc concatenate */
static void T200_expiry ( UBYTE channel, UBYTE sapi)
{
GET_INSTANCE_DATA;
UBYTE old_state;
UBYTE new_state;
T_CCH * pcch = &dl_data->cch[channel];
UBYTE N200_counter;
TRACE_FUNCTION ("T200_expiry()");
switch (pcch->ch_type)
{
case L2_CHANNEL_SACCH:
N200_counter = SACCH_N200;
break;
case L2_CHANNEL_SDCCH:
N200_counter = SDCCH_N200;
break;
case L2_CHANNEL_FACCH_F:
N200_counter = FACCH_N200_FR;
break;
case L2_CHANNEL_FACCH_H:
N200_counter = FACCH_N200_HR;
break;
default:
N200_counter = NOT_PRESENT_8BIT;
break;
}
new_state = old_state = dl_data->state[channel];
switch (old_state)
{
case STATE_CONTENTION_RESOLUTION:
repeat_sabm (channel, sapi);
break;
case STATE_MULTIPLE_FRAME_ESTABLISHED:
pcch->rc = 1;
pcch->p_bit_flag= 1;
pcch->time_flag = TRUE;
new_state = STATE_TIMER_RECOVERY;
break;
case STATE_TIMER_RECOVERY:
if (N200_counter EQ NOT_PRESENT_8BIT)
break; /* invalid channel */
if (pcch->rc >= N200_counter)
{ /* release connection due to T200 expired N200 plus 1 times */
TRACE_EVENT_WIN_P1 ("T200 expired, N200=%u", N200_counter);
/* New! Called now by mdl_error_ind().
* drr_dl_release_ind (dl_data, pcch->ch_type, sapi, NOT_PRESENT_8BIT);
*/
mdl_error_ind (T200_EXPIRED_N200_PLUS_1_TIMES, pcch->ch_type, sapi);
if (sapi EQ PS_SAPI_0)
{
dcch3_init_dl_data();
pcch->T200_counter = 0;
pcch->time_flag = FALSE;
pcch->contention_resolution = FALSE;
pcch->vtx = EMPTY_CMD;
new_state = STATE_IDLE_DL;
}
}
else
{
pcch->rc++;
pcch->p_bit_flag = 1;
pcch->time_flag = TRUE;
}
break;
case STATE_AWAITING_RELEASE:
if (pcch->rc >= N200_ESTABLISHMENT)
{
TRACE_EVENT_WIN_P1 ("T200 expired, N200=%u", N200_ESTABLISHMENT);
drr_dl_release_cnf (pcch->ch_type, sapi, TRUE);
new_state = STATE_IDLE_DL;
}
else
{
pcch->rc++;
pcch->vtx = DISC_CMD;
pcch->time_flag = TRUE;
}
break;
default:
break;
}/* endswitch old_state */
if (new_state NEQ old_state)
{
set_channel_state (channel, new_state);
}
}/* endfunc T200_expiry */
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147) MODULE : state |
| STATE : code ROUTINE : repeat_sabm |
+--------------------------------------------------------------------+
PURPOSE : Repeat if possible the SABM command.
*/
static void repeat_sabm (UBYTE channel, UBYTE sapi)
{
GET_INSTANCE_DATA;
T_CCH* pcch = &dl_data->cch[channel];
TRACE_FUNCTION ("repeat_sabm()");
if (pcch->rc >= N200_ESTABLISHMENT)
{
if (sapi EQ PS_SAPI_0)
pcch->contention_resolution = FALSE;
DL_OFFLINE_TRACE (TRACE_DL_EVENT, channel, pcch->ch_type, ">N200_EST");
SYST_TRACE_P ((SYST, "DL: >N200 of SABM"));
TRACE_ERROR ("DL: >N200 of SABM");
DL_EM_CHANNEL_ESTABLISHMENT_FAILED;
mdl_error_ind(T200_EXPIRED_N200_PLUS_1_TIMES, pcch->ch_type, sapi);
set_channel_state (channel, STATE_IDLE_DL);
/* New! Called now by mdl_error_ind().
* drr_dl_release_ind (dl_data, pcch->ch_type, sapi, NOT_PRESENT_8BIT);
*/
}
else
{
pcch->rc++;
pcch->vtx = SABM_CMD;
pcch->time_flag = TRUE;
TRACE_EVENT_P1 ("DL: T200 %u. repeat of SABM", pcch->rc);
}
}/* endfunc repeat_sabm */
GLOBAL void set_channel_state (UBYTE channel, UBYTE state)
{
GET_INSTANCE_DATA;
if (dl_data->state[channel] NEQ state)
{
#ifdef TRACE_STATE
vsi_o_state_ttrace ("STATE_%s:%s -> %s", PROCESS_NAME[channel],
channel EQ C_DCCH3 ? STATE_DCCH3_NAME[dl_data->state[channel]]:
STATE_DCCH0_NAME[dl_data->state[channel]],
channel EQ C_DCCH3 ? STATE_DCCH3_NAME[state] :
STATE_DCCH0_NAME[state]);
#endif /* TRACE_STATE */
dl_data->state[channel] = state;
DL_OFFLINE_TRACE (TRACE_CHSTATE, channel, dl_data->cch[channel].ch_type, NULL);
}
}/* endfunc set_channel_state */
static void set_T200_counter (T_CCH* pcch, UBYTE sapi)
{
switch (pcch->ch_type)
{
case L2_CHANNEL_SACCH:
pcch->T200_counter = sapi EQ PS_SAPI_0 ?
T200_SDCCH_SAPI_0_CNT : T200_SACCH_SAPI_3_CNT;
break;
default:
TRACE_EVENT_WIN_P1 ("set_T200_counter: unknown ch_type=%u -> use SDCCH", pcch->ch_type);
/*lint -fallthrough*/
case L2_CHANNEL_SDCCH:
pcch->T200_counter = sapi EQ PS_SAPI_0 ?
T200_SDCCH_SAPI_0_CNT : T200_SDCCH_SAPI_3_CNT;
break;
case L2_CHANNEL_FACCH_F:
pcch->T200_counter = T200_FACCH_SAPI_0_CNT_FR;
break;
case L2_CHANNEL_FACCH_H:
pcch->T200_counter = T200_FACCH_SAPI_0_CNT_HR;
break;
}/* endswitch ch_type */
pcch->time_flag = FALSE;
TRACE_EVENT_WIN_P3 ("set_T200_counter: %s, SAPI=%u: %u",
CH_TYPE_NAME[pcch->ch_type], sapi, pcch->T200_counter);
}/* endfunc set_T200_counter */
#if defined(DELAYED_RELEASE_IND)
static void delayed_release_ind( UBYTE channel)
{
GET_INSTANCE_DATA;
/* delay DL RELEASE IND to RR for FTA 25.2.3 *********** */
if (dl_data->release_ind_ch_type NEQ NOT_PRESENT_8BIT)
{
if (dl_data->release_ind_delay > 0)
dl_data->release_ind_delay--;
if (dl_data->release_ind_delay EQ 0)
{
DL_OFFLINE_TRACE (TRACE_DL_EVENT, TRACE_CH_UNKNOWN,
dl_data->release_ind_ch_type, "UL:send delayed REL IND");
drr_dl_release_ind (dl_data->release_ind_ch_type,
dl_data->release_ind_sapi, NOT_PRESENT_8BIT, TRUE);
}
else
{
DL_OFFLINE_TRACE (TRACE_DL_EVENT, TRACE_CH_UNKNOWN,
dl_data->release_ind_ch_type, "UL:pend. delay REL IND");
}
}
}
#endif /* DELAYED_RELEASE_IND */
T_RADIO_FRAME* dl_uplink(UBYTE channel, UBYTE sapi,
UBYTE no_signalling_mode, BOOL recursive)
{
GET_INSTANCE_DATA;
T_CCH* pcch = &dl_data->cch[channel];
T_RADIO_FRAME* p_l2_frame = &dl_data->l2_frame;
int send = UPLINK_NULL;
TRACE_EVENT_WIN_P3 ("uplink(): %s dcch0_ch_type:%s dedi=%u",
CH_TYPE_NAME[pcch->ch_type], CH_TYPE_NAME[dl_data->dcch0_ch_type], dl_data->RR_dedicated);
TRACE_EVENT_WIN_P6 ("UL: DCCH0=%s,%s vr=%u vs=%u va=%u T200=%u",
CH_TYPE_NAME[dl_data->cch[C_DCCH0].ch_type],
STATE_DCCH0_NAME[dl_data->state[C_DCCH0]],
dl_data->cch[C_DCCH0].vr, dl_data->cch[C_DCCH0].vs, dl_data->cch[C_DCCH0].va,
dl_data->cch[C_DCCH0].T200_counter);
TRACE_EVENT_WIN_P6 ("UL: DCCH3=%s,%s vr=%u vs=%u va=%u T200=%u",
CH_TYPE_NAME[dl_data->cch[C_DCCH3].ch_type],
STATE_DCCH3_NAME[dl_data->state[C_DCCH3]],
dl_data->cch[C_DCCH3].vr, dl_data->cch[C_DCCH3].vs, dl_data->cch[C_DCCH3].va,
dl_data->cch[C_DCCH3].T200_counter);
/* check SACCH SAPI and channel */
if (pcch->ch_type EQ L2_CHANNEL_SACCH)
{
if (!dl_data->RR_dedicated)
{
sapi = PS_SAPI_0;
send = UPLINK_EMPTY;
TRACE_EVENT_WIN ("SACCH without dedicated channel: change SAPI->0, UPLINK_EMPTY");
}
else if (dl_data->state[C_DCCH0] EQ STATE_SUSPENDED)
{
sapi = PS_SAPI_0;
send = UPLINK_REPORT;
TRACE_EVENT_WIN ("SACCH during suspended dedicated channel: change SAPI->0, UPLINK_REPORT");
}
else if (sapi EQ PS_SAPI_3)
{
if ((dl_data->state[C_DCCH0] <= STATE_IDLE_DL)
OR
(dl_data->dcch0_ch_type EQ L2_CHANNEL_SDCCH)
OR
((dl_data->cch[C_DCCH3].vtx EQ EMPTY_CMD) AND
(!com_queue_awaiting_transmission (PS_SAPI_3)) AND
(dl_data->state[C_DCCH3] NEQ STATE_AWAITING_ESTABLISHMENT)
) )
{
sapi = PS_SAPI_0;
TRACE_EVENT_WIN ("SACCH with SAPI=3 only together with FACCH and frame is awaiting tx: change SAPI->0");
}
else
{
channel = C_DCCH3;
pcch = &dl_data->cch[channel];
TRACE_EVENT_WIN ("SACCH with SAPI=3 together with FACCH: change channel->C_DCCH3");
}
}
}
else if ((dl_data->RR_dedicated) AND
(dl_data->dcch0_ch_type NEQ pcch->ch_type))
{
TRACE_EVENT_WIN_P2 ("dcch0_ch_type (%s) NEQ %s -> unexpected,unsolicited,invalid channel => UPLINK_EMPTY",
CH_TYPE_NAME[dl_data->dcch0_ch_type],
CH_TYPE_NAME[dl_data->cch[C_DCCH0].ch_type]);
send = UPLINK_EMPTY;
}
/* decrease T200 counter ************************************ */
if (channel EQ C_DCCH3)
{
if (dl_data->cch[C_DCCH3].T200_counter >= T200_ACTIVE)
{
dl_data->cch[C_DCCH3].T200_counter--;
TRACE_EVENT_WIN_P2 ("T200(SAPI_0)=%u T200(SAPI_3)=%u*",
dl_data->cch[C_DCCH0].T200_counter, dl_data->cch[C_DCCH3].T200_counter);
/*DL_OFFLINE_TRACE (TRACE_DL_EVENT, channel, pcch->ch_type, "dec T200(SAPI_3)");*/
}
}
else
{
if (pcch->ch_type NEQ L2_CHANNEL_SACCH) /* no T200 for SACCH with SAPI=0 */
{
if (dl_data->cch[C_DCCH0].T200_counter >= T200_ACTIVE)
{
dl_data->cch[C_DCCH0].T200_counter--;
TRACE_EVENT_WIN_P2 ("T200(SAPI_0)=%u* T200(SAPI_3)=%u",
dl_data->cch[C_DCCH0].T200_counter, dl_data->cch[C_DCCH3].T200_counter);
/*DL_OFFLINE_TRACE (TRACE_DL_EVENT, channel, pcch->ch_type, "dec T200(SAPI_0)");*/
}
}
}
/* check activity of DL ************************************* */
if (dl_data->dl_active AND dl_data->state[channel] EQ STATE_MULTIPLE_FRAME_ESTABLISHED)
{
TRACE_EVENT_WIN_P1 ("uplink(): %s dl_active", PROCESS_NAME[channel]);
DL_OFFLINE_TRACE (TRACE_DL_EVENT, channel, pcch->ch_type, "UL:&dl_active");
/* signalling only */
send = UPLINK_EMPTY;
}/* endif dl_active */
#if defined(DELAYED_SABM)
/* delay uplink SABM to PL for FTA 26.6.6.1 and 25.2.3 *********** */
if ((channel EQ C_DCCH0) AND (dl_data->dcch0_sabm_flag NEQ NOT_PRESENT_8BIT))
{
dcch0_delay_sabm (pcch);
if (dl_data->dcch0_sabm_flag NEQ NOT_PRESENT_8BIT)
send = UPLINK_EMPTY; /* send dummy only */
}
#endif /* DELAYED_SABM */
#if defined(DELAYED_RELEASE_IND)
delayed_release_ind (channel);
#endif /* DELAYED_RELEASE_IND */
if ((send EQ UPLINK_NULL) OR (send EQ UPLINK_EMPTY))
{ /* After a L3 release at the last downlink DL should send a DISC */
TRACE_EVENT_WIN_P6 ("uplink():%s %s SAPI=%u vtx=%s %s (#%u)",
PROCESS_NAME[channel], CH_TYPE_NAME[pcch->ch_type], sapi,
VTX_NAME[pcch->vtx], SEND_NAME[send], __LINE__);
switch (channel)
{
case C_DCCH0:
send = dcch0_check_disc (send);
break;
case C_DCCH3:
send = dcch3_check_disc (send);
break;
default:
break;
}
TRACE_EVENT_WIN_P6 ("uplink():%s %s SAPI=%u vtx=%s %s (#%u)",
PROCESS_NAME[channel], CH_TYPE_NAME[pcch->ch_type], sapi,
VTX_NAME[pcch->vtx], SEND_NAME[send], __LINE__);
}
if (send EQ UPLINK_NULL)
{
TRACE_EVENT_WIN_P5 ("uplink():%s %s SAPI=%u vtx=%s %s",
PROCESS_NAME[channel], CH_TYPE_NAME[pcch->ch_type], sapi,
VTX_NAME[pcch->vtx], recursive ? "RECURSIVE" : "");
TRACE_EVENT_WIN_P8 ("UL: DCCH%u=%s,%s vr=%u vs=%u va=%u T200=%u (#%u)",
sapi, CH_TYPE_NAME[dl_data->cch[channel].ch_type],
STATE_DCCH3_NAME[dl_data->state[channel]],
dl_data->cch[channel].vr, dl_data->cch[channel].vs, dl_data->cch[channel].va,
dl_data->cch[channel].T200_counter, __LINE__);
/* check timer T200 expiry ****************************** */
if ((channel EQ C_DCCH0) AND
(dl_data->cch[C_DCCH0].T200_counter EQ T200_EXPIRED))
T200_expiry (C_DCCH0, PS_SAPI_0);
if ((channel EQ C_DCCH3) AND
(dl_data->cch[C_DCCH3].T200_counter EQ T200_EXPIRED))
T200_expiry (C_DCCH3, PS_SAPI_3);
TRACE_EVENT_WIN_P8 ("UL: DCCH%u=%s,%s vr=%u vs=%u va=%u T200=%u (#%u)",
sapi, CH_TYPE_NAME[dl_data->cch[channel].ch_type],
STATE_DCCH3_NAME[dl_data->state[channel]],
dl_data->cch[channel].vr, dl_data->cch[channel].vs, dl_data->cch[channel].va,
dl_data->cch[channel].T200_counter, __LINE__);
/* state machine **************************************** */
switch (dl_data->state[channel])
{
case STATE_IDLE_DL:
if (pcch->vtx EQ EMPTY_CMD AND !dl_data->RR_dedicated)
break;
send = uplink_idle (channel, sapi);
break;
case STATE_CONTENTION_RESOLUTION: /* the same as STATE_AWAITING_ESTABLISHMENT */
send = uplink_awaiting_establishment (channel, sapi, no_signalling_mode);
break;
case STATE_MULTIPLE_FRAME_ESTABLISHED:
send = uplink_mfe (channel, sapi, no_signalling_mode);
break;
case STATE_TIMER_RECOVERY:
send = uplink_timer_recovery (channel, sapi, no_signalling_mode);
break;
case STATE_AWAITING_RELEASE:
send = uplink_awaiting_release ( channel, sapi);
break;
case STATE_SUSPENDED: /* only DCCH0 */
send = UPLINK_NULL;
break;
case STATE_DISABLED: /* only SABM/UA or SACCH and SDCCH (SAPI 3) */
if (channel EQ C_DCCH3)
{
if (pcch->vtx EQ UA_CMD)
{
send = uplink_idle (channel, sapi);
}
else
{
send = UPLINK_EMPTY;
}
}
break;
}/* endswitch channel_state */
}/* endif send == NULL */
TRACE_EVENT_WIN_P8 ("UL: DCCH%u=%s,%s vr=%u vs=%u va=%u T200=%u (#%u)",
sapi, CH_TYPE_NAME[dl_data->cch[channel].ch_type],
STATE_DCCH3_NAME[dl_data->state[channel]],
dl_data->cch[channel].vr, dl_data->cch[channel].vs, dl_data->cch[channel].va,
dl_data->cch[channel].T200_counter, __LINE__);
if (pcch->ch_type EQ L2_CHANNEL_SACCH)
{ /*
* According to 3GPP TS 04.05, 4.2.2 Priority:
* The priority arrangement on the SACCH must ensure that if a SAPI = 3
* frame is awaiting transmission, two SAPI = 0 frames are not sent in
* consecutive SACCH frames. In addition, for the mobile to network
* direction it must also be ensured that any SAPI = 3 frame is followed
* by at least one SAPI = 0 frame.
*/
TRACE_EVENT_WIN_P3 ("sacch_last_uplink_sapi=%u SAPI=%u send=%s",
dl_data->sacch_last_uplink_sapi, sapi, SEND_NAME[send]);
if ((dl_data->sacch_last_uplink_sapi EQ PS_SAPI_3) OR
((sapi EQ PS_SAPI_3 ) AND (send EQ UPLINK_EMPTY)))
{/* last uplinked SACCH frame was one with SAPI=3
* or
* no SACCH SAPI=3 frame is awaiting transmission
* -> uplink of a SACCH SAPI=0 frame
*/
sapi = PS_SAPI_0;
}
if (send EQ UPLINK_EMPTY)
{
sapi = PS_SAPI_0;
}
if ((sapi EQ PS_SAPI_0) AND (dl_data->state[C_DCCH0] >= STATE_SUSPENDED))
{ /*
* uplink measurement reports only if SAPI=0 is suspended,
* on contention resolution procedure, established or awaiting release
*/
send = UPLINK_REPORT;
TRACE_EVENT_WIN ("uplink(): SACCH REPORT now");
}
TRACE_EVENT_WIN_P2 ("sacch_last_uplink_sapi:=%u->%u", dl_data->sacch_last_uplink_sapi, sapi);
dl_data->sacch_last_uplink_sapi = sapi;
}
else if ((pcch->ch_type EQ L2_CHANNEL_SDCCH) AND (channel NEQ C_DCCH3))
{ /*
* According to 3GPP TS 04.05, 4.2.2 Priority:
* The priority between data links on SDCCH shall be as follows:
* Highest priority : SAPI = 0, Lowest priority : SAPI = 3.
*/
if ((sapi EQ PS_SAPI_0) AND (send <= UPLINK_EMPTY))
{ /* special case: nothing is awaiting transmission for SAPI=0 */
if ((dl_data->cch[C_DCCH3].vtx NEQ EMPTY_CMD) OR
com_queue_awaiting_transmission(PS_SAPI_3) OR
(dl_data->cch[C_DCCH3].T200_counter NEQ T200_STOPPED))
{/* something is awaiting transmission for SAPI=3 */
if (dl_data->state[C_DCCH0] >= STATE_CONTENTION_RESOLUTION)
{ /*
* uplink SAPI=3 only if SAPI=0 is on contention resolution procedure
* or established or awaiting release
*/
send = UPLINK_DCCH3;
}
}
}
}
else
{
/* no special treatment of FACCH */
}
/* return uplink frame buffer pointer dependent on the value of send */
TRACE_EVENT_WIN_P4 ("%s on %s SAPI=%u RR_dedicated=%u",
SEND_NAME[send], CH_TYPE_NAME[pcch->ch_type], sapi, dl_data->RR_dedicated);
switch (send)
{
case UPLINK_NORMAL:
break;
case UPLINK_UA:
case UPLINK_UA_F:
com_build_UA_response (pcch->ch_type, sapi, (UBYTE)((send EQ UPLINK_UA_F) ? 1 : 0));
break;
case UPLINK_IFRAME:
case UPLINK_IFRAME_P:
{
UBYTE m_bit;
UBYTE p_bit = (send EQ UPLINK_IFRAME_P) ? 1 : 0;
T_QUEUE *queue;
if (pcch->ch_type EQ L2_CHANNEL_SACCH)
{
sapi = PS_SAPI_3; /* acknowledged mode only for SAPI=3 */
TRACE_EVENT_WIN ("SACCH with I frame: acknowledged mode only for SAPI=3");
}
if (sapi EQ PS_SAPI_0)
queue = &dl_data->dcch0_queue;
else
queue = &dl_data->dcch3_queue;
if (send EQ UPLINK_IFRAME)
{
com_read_queue (pcch->ch_type, sapi, &m_bit);
}
else
{/* TIMER_RECOVERY state -> repetition of the last frame */
pcch->vs--;
pcch->vs &= 7;
pcch->p_bit_flag = 0;
m_bit = queue->m_bit; /* remember last m bit */
TRACE_EVENT_WIN_P2 ("TIMER_RECOVERY state: decrement vs to %u, remember m=%u", pcch->vs, m_bit);
}
com_build_I_command (pcch->ch_type, sapi, pcch->vs, pcch->vr,
p_bit, m_bit, queue);
pcch->vs++;
pcch->vs &= 7;
TRACE_EVENT_WIN_P4 ("%s SAPI=%u new vs=%u (pcch=%08x)",
CH_TYPE_NAME[pcch->ch_type], sapi, pcch->vs, pcch);
}
set_T200_counter (pcch, sapi);
break;
case UPLINK_RR:
case UPLINK_RR_F:
if (pcch->ch_type EQ L2_CHANNEL_SACCH)
{/*
* There are some tests at the start of dl_uplink() to determine the right
* SAPI value for SACCH. But the resulting value may be wrong because of
* the priority arrangement according to 3GPP TS 04.05, section 4.2.2.
* In case the MS has to uplink a RR frame it is clear that
* L2 is in acknowledged mode and this can be done only with
* a SAPI value of 3 for SACCH.
*/
sapi = PS_SAPI_3; /* acknowledged mode only for SAPI=3 */
TRACE_EVENT_WIN ("SACCH with supervisory frame: acknowledged mode only for SAPI=3");
}
com_build_RR_response (pcch->ch_type, sapi, pcch->vr,
(UBYTE)((send EQ UPLINK_RR_F) ? 1 : 0));
break;
case UPLINK_REJ:
case UPLINK_REJ_F:
if (pcch->ch_type EQ L2_CHANNEL_SACCH)
{/*
* There are some tests at the start of dl_uplink() to determine the right
* SAPI value for SACCH. But the resulting value may be wrong because of
* the priority arrangement according to 3GPP TS 04.05, section 4.2.2.
* In case the MS has to uplink a REJ frame it is clear that
* L2 is in acknowledged mode and this can be done only with
* a SAPI value of 3 for SACCH.
*/
sapi = PS_SAPI_3; /* acknowledged mode only for SAPI=3 */
TRACE_EVENT_WIN ("SACCH with supervisory frame: acknowledged mode only for SAPI=3");
}
com_build_REJ_response (pcch->ch_type, sapi, pcch->vr,
(UBYTE)((send EQ UPLINK_REJ_F) ? 1 : 0));
break;
case UPLINK_REPORT:
if (dl_data->RR_dedicated)
{/* measurement report only in RR dedicated mode */
sacch0_send_data ();
com_l3trace (TRACE_UACK_UP, pcch->ch_type, (UBYTE *)p_l2_frame+5);
/* no deleting of vtx!!! */
return p_l2_frame;
/* break; not necessary */
}/* endif measurement report only in RR dedicated mode */
/* else go through to UPLINK_EMPTY */
/*lint -fallthrough*/
default:
possible_reset_dcch0_ch_type();
/* check RR message with short PD, short L2 header type 1, format Bter */
if ((dl_data->state[C_DCCH0] >= STATE_SUSPENDED) AND
dl_data->rr_short_pd_buffer.l_buf AND
(dl_data->rr_short_pd_ch_type EQ pcch->ch_type))
{ /* RR message with short PD, short L2 header type 1, format Bter */
com_build_UI_Bter (pcch->ch_type);
return p_l2_frame;
}
if (((pcch->ch_type EQ L2_CHANNEL_FACCH_F) OR
(pcch->ch_type EQ L2_CHANNEL_FACCH_H))
AND
((no_signalling_mode NEQ SIG_ONLY)
#if defined(DELAYED_SABM)
OR
/* suppress UI frames if delayed SABM is pending
* (independent from signalling mode) */
(dl_data->dcch0_sabm_flag NEQ NOT_PRESENT_8BIT)
#endif /* DELAYED_SABM */
#if defined(DELAYED_RELEASE_IND)
OR
(dl_data->release_ind_ch_type NEQ NOT_PRESENT_8BIT)
#endif /* DELAYED_RELEASE_IND */
))
{
TRACE_EVENT_WIN ("UPLINK_NULL return");
return NULL;
}
/* break; not necessary */
{
T_RADIO_FRAME* empty_frame;
TRACE_EVENT_WIN ("UPLINK_EMPTY return");
/* The use of one byte array instead of two T_RADIO_FRAME structures
* saves 21 byte. Casting is in this case the better way then two calls
* of memcpy.
*/
if (pcch->ch_type EQ L2_CHANNEL_SACCH)
empty_frame = (T_RADIO_FRAME*)(&l2_empty_frame[0]);
else
empty_frame = (T_RADIO_FRAME*)(&l2_empty_frame[2]);
ATRC (empty_frame, 23);
return empty_frame;
}
/* break; not necessary */
case UPLINK_DCCH3:
return dl_uplink (C_DCCH3, PS_SAPI_3, no_signalling_mode, TRUE);
/* break; not necessary */
}/* endswitch send */
/*
* UPLINK_NORMAL, UPLINK_IFRAME (_P), UPLINK_UA (_F),
* UPLINK_RR (_F), UPLINK_REJ (_F)
*/
TRACE_EVENT_WIN_P5 ("%s SAPI=%u delete vtx=%s ->EMPTY_CMD (%s#%u)",
CH_TYPE_NAME[pcch->ch_type], sapi, VTX_NAME[pcch->vtx], __FILE10__, __LINE__);
pcch->vtx = EMPTY_CMD;
possible_reset_dcch0_ch_type();
return p_l2_frame;
}/* endfunc dl_uplink */
static int uplink_idle (UBYTE channel, UBYTE sapi)
{
GET_INSTANCE_DATA;
T_CCH* pcch = &dl_data->cch[channel];
int ret = UPLINK_NORMAL;
int ua_response = FALSE;
TRACE_EVENT_WIN_P3 ("uplink_idle(): %s %s SAPI=%d",
PROCESS_NAME[channel], CH_TYPE_NAME[pcch->ch_type], sapi);
switch (channel)
{
case C_DCCH0:
switch (pcch->vtx)
{
case UA_CMD:
ret = pcch->f_bit ? UPLINK_UA_F : UPLINK_UA;
break;
case DM_CMD:
com_build_DM_response (pcch->ch_type, sapi, pcch->f_bit);
break;
default:
ret = UPLINK_EMPTY;/* no SAPI=3 frame if DCCH0 is idle */
break;
}
break;
case C_DCCH3:
switch (pcch->vtx)
{
case UA_CMD:
ua_response = TRUE;
ret = pcch->f_bit ? UPLINK_UA_F : UPLINK_UA;
break;
case DM_CMD:
com_build_DM_response (pcch->ch_type, PS_SAPI_3, 1);
ret = UPLINK_NORMAL;
break;
default:
ret = UPLINK_EMPTY;
break;
}
break;
}/* endswitch channel */
if (ua_response AND (ret EQ UPLINK_UA_F))
{
drr_dl_establish_ind (pcch->ch_type, sapi,
(UBYTE)(com_queue_awaiting_transmission (sapi) ? DL_UNSERVED : DL_ALL_DONE));
set_channel_state (channel, STATE_MULTIPLE_FRAME_ESTABLISHED);
}
return ret;
}/* endfunc uplink_idle */
static int uplink_awaiting_establishment (UBYTE channel, UBYTE sapi,
UBYTE no_signalling_mode)
{
GET_INSTANCE_DATA;
T_CCH* pcch = &dl_data->cch[channel];
int ret = UPLINK_NORMAL;
int ua_response = FALSE;
int sabm_command = 0;
TRACE_EVENT_WIN_P3 ("uplink_awaiting_establishment(): %s %s SAPI=%d",
PROCESS_NAME[channel], CH_TYPE_NAME[pcch->ch_type], sapi);
if (pcch->time_flag)
set_T200_counter (pcch, sapi);
switch (channel)
{
case C_DCCH0:
if (pcch->vtx EQ SABM_CMD)
{
if (pcch->contention_resolution)
sabm_command = 2; /* com_build_SABM with L3 */
else
sabm_command = 1; /* com_build_SABM without L3 */
}
else
{
ret = UPLINK_EMPTY;/* no SAPI=0 frame is waiting transmission */
}
break;
case C_DCCH3:
switch (pcch->vtx)
{
case SABM_CMD:
sabm_command = 1; /* com_build_SABM without L3 */
break;
case UA_CMD:
ua_response = TRUE;
break;
case DM_CMD:
com_build_DM_response (pcch->ch_type, sapi, pcch->f_bit);
break;
default:
ret = UPLINK_EMPTY;
break;
}
break;
}
if (ua_response)
{
drr_dl_establish_cnf (pcch->ch_type, sapi);
set_channel_state (channel, STATE_MULTIPLE_FRAME_ESTABLISHED);
ret = pcch->f_bit ? UPLINK_UA_F : UPLINK_UA;
}
else if (sabm_command)
{
com_build_SABM(pcch->ch_type, sapi, sabm_command EQ 2);
}
return ret;
}/* endfunc uplink_awaiting_establishment */
static int uplink_mfe (UBYTE channel, UBYTE sapi, UBYTE no_signalling_mode)
{
GET_INSTANCE_DATA;
T_CCH* pcch = &dl_data->cch[channel];
int ret = UPLINK_NORMAL;
TRACE_EVENT_WIN_P6 ("uplink_mfe(): %s:%s SAPI=%d vtx=%s (vs=%u va+1=%u)",
PROCESS_NAME[channel], CH_TYPE_NAME[pcch->ch_type], sapi,
VTX_NAME[pcch->vtx], pcch->vs, (pcch->va + 1)&7 );
if (pcch->time_flag)
set_T200_counter (pcch, sapi);
switch (pcch->vtx)
{
case RR_CMD:
if (pcch->f_bit_flag)
{
ret = UPLINK_RR_F;
pcch->f_bit_flag = 0;
}
else
{
if (!com_queue_awaiting_transmission (sapi))
ret = UPLINK_RR;
else
{
if (pcch->vs EQ ((pcch->va + 1)&7))
ret = UPLINK_RR;
else
ret = UPLINK_IFRAME;
}
}
break;
case UA_CMD:
ret = pcch->f_bit ? UPLINK_UA_F : UPLINK_UA;
break;
case RR_RSP:
ret = pcch->f_bit ? UPLINK_RR_F : UPLINK_RR;
pcch->f_bit_flag = 0;
break;
case REJ_CMD:
ret = pcch->f_bit ? UPLINK_REJ_F : UPLINK_REJ;
pcch->f_bit_flag = 0;
break;
default: /* vtx = ELSE */
switch (channel)
{
case C_DCCH0:
if (com_queue_awaiting_transmission (PS_SAPI_0)
AND
(pcch->vs NEQ ((pcch->va + 1)&7)))
ret = UPLINK_IFRAME;
else
{
ret = UPLINK_EMPTY;/* no SAPI=0 frame is waiting transmission */
}
break;
case C_DCCH3:
if (com_queue_awaiting_transmission (PS_SAPI_3))
{
if (pcch->vs EQ ((pcch->va + 1)&7))
ret = UPLINK_EMPTY;
else
ret = UPLINK_IFRAME;
}
else
{
ret = dcch3_check_disc (UPLINK_EMPTY);/* no SAPI=3 frame is waiting transmission */
}
break;
}/* endswitch channel */
break;
}/* endswitch vtx */
return ret;
}/* endfunc uplink_mfe */
static int uplink_timer_recovery (UBYTE channel, UBYTE sapi, UBYTE no_signalling_mode)
{
GET_INSTANCE_DATA;
T_CCH* pcch = &dl_data->cch[channel];
int ret = UPLINK_NORMAL;
TRACE_EVENT_WIN_P3 ("uplink_timer_recovery(): %s %s SAPI=%d",
PROCESS_NAME[channel], CH_TYPE_NAME[pcch->ch_type], sapi);
if (pcch->time_flag)
set_T200_counter (pcch, sapi);
switch (pcch->vtx)
{
case RR_CMD:
if (pcch->f_bit_flag)
{
ret = UPLINK_RR_F;
pcch->f_bit_flag = 0;
}
else
{
if (pcch->p_bit_flag)
ret = UPLINK_IFRAME_P;
else
ret = UPLINK_RR;
}
break;
case UA_CMD:
ret = pcch->f_bit ? UPLINK_UA_F : UPLINK_UA;
break;
case RR_RSP:
ret = pcch->f_bit ? UPLINK_RR_F : UPLINK_RR;
pcch->f_bit_flag = 0;
break;
case REJ_CMD:
ret = pcch->f_bit ? UPLINK_REJ_F : UPLINK_REJ;
pcch->f_bit_flag = 0;
break;
default: /* vtx = ELSE */
TRACE_EVENT_WIN_P3 ("%s SAPI=%u vtx=%s",
CH_TYPE_NAME[pcch->ch_type], sapi, VTX_NAME[pcch->vtx]);
if (pcch->p_bit_flag)
ret = UPLINK_IFRAME_P;
else
switch (channel)
{
case C_DCCH0:
ret = UPLINK_EMPTY;/* no SAPI=0 frame is waiting transmission */
break;
case C_DCCH3:
ret = dcch3_check_disc (UPLINK_EMPTY);/* no SAPI=3 frame is waiting transmission */
break;
}
break;
}
#if 0 /* decrement first short before sending the frame */
if (ret EQ UPLINK_IFRAME_P)
{
pcch->vs--;
pcch->vs &= 7;
pcch->p_bit_flag = 0;
}
#endif /* 0 */
return ret;
}/* endfunc uplink_timer_recovery */
GLOBAL int uplink_awaiting_release (UBYTE channel, UBYTE sapi)
{
GET_INSTANCE_DATA;
T_CCH* pcch = &dl_data->cch[channel];
int ret = UPLINK_NORMAL;
TRACE_EVENT_WIN_P3 ("uplink_awaiting_release(): %s %s SAPI=%d",
PROCESS_NAME[channel], CH_TYPE_NAME[pcch->ch_type], sapi);
if (pcch->time_flag)
set_T200_counter (pcch, sapi);
switch (pcch->vtx)
{
case DISC_CMD:
/* DL_OFFLINE_TRACE (TRACE_DL_EVENT, channel, pcch->ch_type, "UL:Send DISC"); */
com_build_DISC_command (pcch->ch_type, sapi, 1);
break;
case UA_CMD:
set_channel_state (channel, STATE_IDLE_DL);
#if defined(DELAYED_RELEASE_IND)
switch (pcch->ch_type)
{
#if defined(DL_FACCH_RELEASE_DELAY_VALUE) && (DL_FACCH_RELEASE_DELAY_VALUE > 0)
case L2_CHANNEL_FACCH_F:
case L2_CHANNEL_FACCH_H:
/* delay DL RELEASE IND to RR for testcase 25.2.3 */
dl_data->release_ind_ch_type = pcch->ch_type;
dl_data->release_ind_sapi = sapi;
if (dl_data->release_ind_delay EQ 0)
{
dl_data->release_ind_delay = DL_FACCH_RELEASE_DELAY_VALUE;
DL_OFFLINE_TRACE (TRACE_DL_EVENT, C_DCCH0, pcch->ch_type, "delay REL IND on FACCH");
}
break;
#endif /* DL_FACCH_RELEASE_DELAY_VALUE */
#if defined(DL_SDCCH_RELEASE_DELAY_VALUE) && (DL_SDCCH_RELEASE_DELAY_VALUE > 0)
case L2_CHANNEL_SDCCH:
/* delay DL RELEASE IND to RR for testcase 25.2.3 */
dl_data->release_ind_ch_type = pcch->ch_type;
dl_data->release_ind_sapi = sapi;
if (dl_data->release_ind_delay EQ 0)
{
dl_data->release_ind_delay = DL_SDCCH_RELEASE_DELAY_VALUE;
DL_OFFLINE_TRACE (TRACE_DL_EVENT, channel, pcch->ch_type, "delay REL IND on SDCCH");
}
break;
#endif /* DL_SDCCH_RELEASE_DELAY_VALUE */
default:
drr_dl_release_ind (pcch->ch_type, sapi, NOT_PRESENT_8BIT, TRUE);
break;
}
#else /* DELAYED_RELEASE_IND */
drr_dl_release_ind (pcch->ch_type, sapi, NOT_PRESENT_8BIT, TRUE);
#endif /* DELAYED_RELEASE_IND */
#if defined(LATE_LEAVING_DEDICATED)
com_leave_dedicated (pcch->ch_type);
#endif /* LATE_LEAVING_DEDICATED */
ret = UPLINK_UA_F;
break;
default:
switch (pcch->ch_type)
{
case L2_CHANNEL_SACCH:
if (channel EQ C_DCCH0)
ret = UPLINK_REPORT;
break;
default:
if (channel EQ C_DCCH0)
{
pcch = &dl_data->cch[C_DCCH3];
if (pcch->time_flag)
set_T200_counter (pcch, PS_SAPI_3);
}
ret = UPLINK_EMPTY;
break;
}/* endswitch channel */
}/* endswitch vtx */
return ret;
}/* endfunc uplink_awaiting_release */
#if defined(CHECK_PCCHI)
static void check_pcch_i (T_CCH_INTERN* pcch_i, int line)
{
char buf[23];
int ret = 0;
if (pcch_i EQ NULL)
ret = -1;
else if (pcch_i->pcch EQ NULL)
ret = -2;
if (ret)
{
sprintf (buf, "#%d pcch=NULL %d", line, -ret);
DL_OFFLINE_TRACE (TRACE_DL_EVENT, TRACE_CH_UNKNOWN, 0,buf);
}
return ret;
}/* endfunc check_pcch_i */
#endif /* CHECK_PCCHI */
#endif /* DL_C */