FreeCalypso > hg > fc-selenite
view src/g23m-gsm/dl/dl_state.c @ 180:e69e6b9a28b5
src/g23m-aci: sync with Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 04 Jan 2020 21:44:15 +0000 |
parents | c7e5cb543a53 |
children |
line wrap: on
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 */