FreeCalypso > hg > fc-tourmaline
diff src/g23m-gsm/cc/cc_act.c @ 1:fa8dc04885d8
src/g23m-*: import from Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 16 Oct 2020 06:25:50 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/g23m-gsm/cc/cc_act.c Fri Oct 16 06:25:50 2020 +0000 @@ -0,0 +1,2312 @@ +/* ++----------------------------------------------------------------------------- +| Project : GSM-PS (6147) +| Modul : CC_ACT ++----------------------------------------------------------------------------- +| 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 primitive processing functions +| of the SDL process Call Control for the call active +| phase of the component CC of the mobile station ++----------------------------------------------------------------------------- +*/ + +#ifndef CC_ACT_C +#define CC_ACT_C + +#define ENTITY_CC +/*==== INCLUDES ===================================================*/ + +#include <string.h> +#include "typedefs.h" +#include "pcm.h" +#include "vsi.h" +#include "custom.h" +#include "gsm.h" +#include "message.h" +#include "ccdapi.h" +#include "prim.h" +#include "cnf_cc.h" +#include "mon_cc.h" +#include "pei.h" +#include "tok.h" +#include "cc.h" +#include "cc_em.h" + +/*==== EXPORT =====================================================*/ + +/*==== PROTOTYPES =================================================*/ +LOCAL void cc_mncc_hold_retrieve_req (T_PRIM * prim); + +/*==== PRIVAT =====================================================*/ + +/*==== VARIABLES ==================================================*/ + +/*==== FUNCTIONS ==================================================*/ + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_dtmf_full | ++--------------------------------------------------------------------+ + + PURPOSE : Check whether DTMF buffer is full + +*/ + +LOCAL BOOL cc_dtmf_full (const T_DTMF *p_dtmf) +{ + TRACE_FUNCTION ("cc_dtmf_full()"); + + return ((p_dtmf->read EQ p_dtmf->write + 1) OR + (p_dtmf->read EQ 0 AND p_dtmf->write EQ DTMF_BUF_SIZE - 1)); +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_dtmf_empty | ++--------------------------------------------------------------------+ + + PURPOSE : Check whether DTMF buffer is empty + +*/ + +LOCAL BOOL cc_dtmf_empty (const T_DTMF *p_dtmf) +{ + TRACE_FUNCTION ("cc_dtmf_empty()"); + + return (p_dtmf->read EQ p_dtmf->write); +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_dtmf_write | ++--------------------------------------------------------------------+ + + PURPOSE : Write next entry into DTMF buffer. + No checks are done (e.g. buffer full) + +*/ + +LOCAL void cc_dtmf_write (T_DTMF *p_dtmf, UBYTE val) +{ + TRACE_FUNCTION ("cc_dtmf_write()"); + + p_dtmf->buf[p_dtmf->write++] = val; + if (p_dtmf->write EQ DTMF_BUF_SIZE) + p_dtmf->write = 0; +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_dtmf_write | ++--------------------------------------------------------------------+ + + PURPOSE : Read next entry from DTMF buffer. + No checks are done (e.g. buffer empty) + +*/ + +LOCAL UBYTE cc_dtmf_read (T_DTMF *p_dtmf) +{ + UBYTE val; + + TRACE_FUNCTION ("cc_dtmf_read()"); + + val = p_dtmf->buf[p_dtmf->read++]; + if (p_dtmf->read EQ DTMF_BUF_SIZE) + p_dtmf->read = 0; + return val; +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_dtmf_allowed | ++--------------------------------------------------------------------+ + + PURPOSE : This functions returns TRUE if DTMF is allowed in the + current state, otherwise FALSE. + +*/ + +LOCAL BOOL cc_dtmf_allowed (void) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_dtmf_allowed()"); + + /* + * "The mobile station shall be capable of transmitting DTMF messages if + * and only if the mobile station has the user connection for speech + * attached and an appropriate channel is available. + * + * ".." + * + * NOTE 1: This specification means that DTMF messages can generally be + * sent in the active state of a call in speech transmission + * mode or when a traffic channel is available during setup or + * release and the progress indicator IE has been received." + * + * [TS 24.008 subclause 5.5.7] + * + * As of GSM 04.08 the progress indicator IE can be received by + * CALL PROCEEDING, PROGRESS, CONNECT, SETUP, ALERTING and DISCONNECT. + */ + switch (cc_data->state[cc_data->index_ti]) + { + case M_CC_CS_3: /* mobile originating call proceeding */ + case M_CC_CS_4: /* call delivered */ + case M_CC_CS_8: /* connect request */ + case M_CC_CS_11: /* disconnect request */ + case M_CC_CS_12: /* disconnect indication */ + case M_CC_CS_19: /* release request */ + case CS_101: /* substate of CS_10, reestablish requested */ + case M_CC_CS_26: /* mobile originating modify */ + case CS_261: /* substate of CS_26, reestablish requested */ + if (cc_data->progress_desc[cc_data->index_ti] EQ NOT_PRESENT_8BIT) + return FALSE; /* Progress indicator IE has not been received */ + /*FALLTHROUGH*/ /*lint -fallthrough*/ + case M_CC_CS_10: /* active */ + if (cc_data->channel_type EQ NAS_CH_SDCCH) + return FALSE; /* No TCH assigned */ + + if ((cc_data->channel_mode NEQ NAS_CHM_SPEECH) AND + (cc_data->channel_mode NEQ NAS_CHM_SPEECH_V2) AND + (cc_data->channel_mode NEQ NAS_CHM_SPEECH_V3)) + return FALSE; /* Channel mode is not speech */ + + return TRUE; + + default: + return FALSE; + } +} + +/*==== VARIABLES ==================================================*/ + +/*==== FUNCTIONS ==================================================*/ + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mncc_start_dtmf_req | ++--------------------------------------------------------------------+ + + PURPOSE : Sending of DTMF tones to the infrastructure side. + +*/ + +GLOBAL void cc_mncc_start_dtmf_req (T_MNCC_START_DTMF_REQ * dtmf) +{ + GET_INSTANCE_DATA; + T_DTMF * p_dtmf; + + TRACE_FUNCTION ("cc_mncc_start_dtmf_req()"); + + + if ((cc_data->index_ti = srv_convert_ti (dtmf->ti)) + EQ NOT_PRESENT_8BIT) + { + PFREE (dtmf); + return; + } + + switch (cc_data->state[cc_data->index_ti]) + { + default: + if (!cc_dtmf_allowed ()) + { + /* Tone dropped. Confirm DTMF request with negative cause */ + PALLOC (dtmf_cnf, MNCC_START_DTMF_CNF); + dtmf_cnf->ti = dtmf->ti; + dtmf_cnf->key = dtmf->key; + dtmf_cnf->cause = MNCC_CAUSE_DTMF_NOT_ALLOWED; + dtmf_cnf->dtmf_mod = dtmf->dtmf_mod; + PSENDX (MMI, dtmf_cnf); + + PFREE (dtmf); + return; + } + + p_dtmf = &cc_data->dtmf [cc_data->index_ti]; + + if ( dtmf->dtmf_mod EQ MNCC_DTMF_MOD_AUTO OR + dtmf->dtmf_mod EQ MNCC_DTMF_MOD_MAN_START ) + { + if (p_dtmf->state EQ DTMF_IDLE) + { + /* + * If sending of DTMF tones is not in + * progress send the tone. + */ + CCD_START; + { + MCAST (start_dtmf, U_START_DTMF); + + cc_build_start_dtmf (dtmf->key, start_dtmf); + for_start_dtmf (start_dtmf); + } + CCD_END; + + /* On sending a START DTMF message the MS shall start T336 */ + TIMERSTART (T336, T336_VALUE); + + p_dtmf->state = DTMF_SEND_REQUEST; + p_dtmf->mode = (dtmf->dtmf_mod EQ MNCC_DTMF_MOD_AUTO)?DTMF_AUTO:DTMF_MAN; + p_dtmf->key = dtmf->key; + } + else + { + /* + * Not DTMF_IDLE. + */ + + if (dtmf->dtmf_mod EQ MNCC_DTMF_MOD_AUTO) + { + /* + * If DTMF_MOD_AUTO, store the tone if the buffer is not full. + */ + if (!cc_dtmf_full (p_dtmf)) + cc_dtmf_write (p_dtmf, (UBYTE)SET_DTMF_MOD(dtmf->key, DTMF_AUTO)); + // PATCH HM 13.04.00 >>> + else + { + /* Tone dropped. Confirm DTMF request with negative cause */ + PALLOC (dtmf_cnf, MNCC_START_DTMF_CNF); + dtmf_cnf->ti = dtmf->ti; + dtmf_cnf->key = dtmf->key; + dtmf_cnf->cause = MNCC_CAUSE_DTMF_BUFFER_FULL; + dtmf_cnf->dtmf_mod = dtmf->dtmf_mod; + PSENDX(MMI, dtmf_cnf); + } + // PATCH HM 13.04.00 <<< + } + else + { + /* + * If DTMF_MOD_MAN_START, two conditions have to be fullfilled + * that the tone is stored and not dropped: + * + * - The buffer is not full. + * - There is enough room to store the stop which + * will follow the tone. + */ + if (!cc_dtmf_full (p_dtmf) AND + (p_dtmf->read NEQ (p_dtmf->write + 2) % DTMF_BUF_SIZE)) + { + cc_dtmf_write (p_dtmf, (UBYTE)SET_DTMF_MOD(dtmf->key, DTMF_MAN)); + } + // PATCH HM 13.04.00 >>> + else + { + /* Tone dropped. Confirm DTMF request with negative cause */ + PALLOC (dtmf_cnf, MNCC_START_DTMF_CNF); + dtmf_cnf->ti = dtmf->ti; + dtmf_cnf->key = dtmf->key; + dtmf_cnf->cause = MNCC_CAUSE_DTMF_BUFFER_FULL; + dtmf_cnf->dtmf_mod = dtmf->dtmf_mod; + PSENDX (MMI, dtmf_cnf); + } + // PATCH HM 13.04.00 <<< + } + } + } + else + { + /* + * This is DTMF_MOD_MAN_STOP + */ + if ( p_dtmf->state EQ DTMF_SEND_ACKNOWLEDGE AND + cc_dtmf_empty (p_dtmf)) + { + /* + * If sending of DTMF tones is in + * progress stop the tone. + */ + for_stop_dtmf (); + + /* On sending a STOP DTMF message the MS shall start T337 */ + TIMERSTART (T337, T337_VALUE); + + p_dtmf->state = DTMF_STOP_REQUEST; + } + else + { + /* + * If DTMF_MOD_MAN_STOP, the stop mark is stored if + * the buffer is not full. If DTMF STOP ACK is received + * and there are unexpected stops in the buffer due to + * a loss of the respective tones, the stops are dropped + * until a tone is found. + */ + if (!cc_dtmf_full(p_dtmf)) + { + cc_dtmf_write (p_dtmf, NOT_PRESENT_8BIT); + } + } + } + PFREE (dtmf) + break; + + case M_CC_CS_26: /* mobile originating modify */ + case CS_101: + case CS_261: + srv_store_prim ((T_PRIM *)D2P(dtmf)); + break; + } +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_reset_dtmf | ++--------------------------------------------------------------------+ + + PURPOSE : Reset DTMF machine. If used before CC leaves any state in + which DTMF is possible MMI is informed about DTMF failure + if there was still a DTMF request outstanding. + +*/ + +GLOBAL void cc_reset_dtmf (void) +{ + GET_INSTANCE_DATA; + T_DTMF * p_dtmf; + BOOL dtmf_aborted; + + TRACE_FUNCTION ("cc_reset_dtmf"); + + p_dtmf = &cc_data->dtmf[cc_data->index_ti]; + + if (cc_dtmf_allowed()) + { + /* Stop all possibly running DTMF timers */ + TIMERSTOP (TIMER_DTMF); + + /* + * A DTMF acknowledge maybe outstanding for ACI either if the + * DTMF state is DTMF_SEND_REQ or + * a tone was found in the DTMF send buffer + */ + dtmf_aborted = (p_dtmf->state EQ DTMF_SEND_REQUEST); + while (!dtmf_aborted AND !cc_dtmf_empty(p_dtmf)) + dtmf_aborted = (cc_dtmf_read (p_dtmf) NEQ NOT_PRESENT_8BIT); + + if (dtmf_aborted) + { + /* Tone dropped. Confirm DTMF request with negative cause */ + PALLOC (dtmf_cnf, MNCC_START_DTMF_CNF); + dtmf_cnf->ti = cc_data->ti; + dtmf_cnf->key = NOT_PRESENT_8BIT; + dtmf_cnf->cause = MNCC_CAUSE_DTMF_ABORTED; + dtmf_cnf->dtmf_mod = NOT_PRESENT_8BIT; + PSENDX (MMI, dtmf_cnf); + } + + } + p_dtmf->state = DTMF_IDLE; + p_dtmf->write = 0; + p_dtmf->read = 0; +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_start_dtmf_ack | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming start dtmf acknowledge message. + +*/ + +GLOBAL void cc_start_dtmf_ack (T_D_START_DTMF_ACK * start_dtmf_ack) +{ + GET_INSTANCE_DATA; + T_DTMF * p_dtmf; + + TRACE_FUNCTION ("cc_start_dtmf_ack()"); + + if (cc_dtmf_allowed ()) + { + if (cc_check_error_flag ()) + { + p_dtmf = &cc_data->dtmf[cc_data->index_ti]; + + /* Stop T336 */ + TIMERSTOP (TIMER_DTMF); + + if (p_dtmf->state EQ DTMF_SEND_REQUEST) + { + PALLOC (start, MNCC_START_DTMF_CNF); + + start->ti = cc_data->ti; + start->key = start_dtmf_ack->key_facility.key; + start->cause = MNCC_CAUSE_DTMF_START_SUCCESS; + start->dtmf_mod = (p_dtmf->mode EQ DTMF_AUTO) ? + MNCC_DTMF_MOD_AUTO : MNCC_DTMF_MOD_MAN_START; + PSENDX (MMI, start); + + EM_CC_START_DTMF_ACKNOWLEDGE; + + if( p_dtmf->mode EQ DTMF_AUTO ) + { + for_stop_dtmf (); + + /* On sending a STOP DTMF message the MS shall start T337 */ + TIMERSTART (T337, T337_VALUE); + + p_dtmf->state = DTMF_STOP_REQUEST; + } + else + { + /* This is DTMF_MAN */ + if (!cc_dtmf_empty (p_dtmf)) + { + UBYTE tone; + + tone = cc_dtmf_read (p_dtmf); + if (tone EQ NOT_PRESENT_8BIT) + { + /* Should be always true */ + p_dtmf->mode = GET_DTMF_MOD(tone); + for_stop_dtmf (); + + /* On sending a STOP DTMF message the MS shall start T337 */ + TIMERSTART (T337, T337_VALUE); + + p_dtmf->state = DTMF_STOP_REQUEST; + } + while (!cc_dtmf_empty(p_dtmf) AND + p_dtmf->buf[p_dtmf->read] EQ NOT_PRESENT_8BIT) + { + /* Consume all unwanted stop marks */ + (void)cc_dtmf_read(p_dtmf); + } + } + else + p_dtmf->state = DTMF_SEND_ACKNOWLEDGE; + } +/* Implements Measure# 3 and streamline encoding */ + CCD_END; + } + else + { + +/* Implements Measure# 3 and streamline encoding */ + CCD_END; + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + } +/* Implements Measure# 3 and streamline encoding */ + } /* if (cc_check_error_flag (cc_data)) */ + } /* if (cc_dtmf_allowed (cc_data)) */ + else + { + /* + * DTMF not allowed for some reason, e.g. wrong state, + * call is not a speech call, no TCH assigned etc. + */ + CCD_END; +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + } +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_start_dtmf_rej | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming start dtmf reject message. + +*/ + +GLOBAL void cc_start_dtmf_rej (T_D_START_DTMF_REJ * start_dtmf_rej) +{ + GET_INSTANCE_DATA; + T_DTMF * p_dtmf; + + TRACE_FUNCTION ("cc_start_dtmf_rej()"); + + if (cc_dtmf_allowed ()) + { + if (cc_check_error_flag ()) + { + /* Stop T336 */ + TIMERSTOP (TIMER_DTMF); + p_dtmf = &cc_data->dtmf[cc_data->index_ti]; + if (p_dtmf->state EQ DTMF_SEND_REQUEST) + { + PALLOC (start, MNCC_START_DTMF_CNF); + + start->ti = cc_data->ti; + start->key = NOT_PRESENT_8BIT; + start->dtmf_mod = NOT_PRESENT_8BIT; + /* + * cause IE is mandatory and the check for presence has been done already + * thus there is no need to check for validity of cause IE here anymore + */ + start->cause = CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_NET, + MNCC_CC_ORIGINATING_ENTITY, + start_dtmf_rej->cc_cause.cause); + PSENDX (MMI, start); + + p_dtmf->state = DTMF_IDLE; + p_dtmf->write = 0; + p_dtmf->read = 0; +/* Implements Measure# 3 and streamline encoding */ + CCD_END; + } + else + { +/* Implements Measure# 3 and streamline encoding */ + CCD_END; + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + } +/* Implements Measure# 3 and streamline encoding */ + } + } + else + { + /* + * DTMF not allowed for some reason, e.g. wrong state, + * call is not a speech call, no TCH assigned etc. + */ + CCD_END; +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + } +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_stop_dtmf | ++--------------------------------------------------------------------+ + + PURPOSE : Stops DTMF, back to DTMF_IDLE state. + Reasons for call: + 1.) Reception of STOP DTMF ACK message + 2.) Expiry of T336 + 3.) Expiry of T337 + +*/ + +GLOBAL void cc_stop_dtmf (void) +{ + GET_INSTANCE_DATA; + T_DTMF * p_dtmf; + + TRACE_FUNCTION ("cc_stop_dtmf()"); + + p_dtmf = &cc_data->dtmf[cc_data->index_ti]; + + while (!cc_dtmf_empty(p_dtmf)) + { + UBYTE tone; + + tone = cc_dtmf_read (p_dtmf); + if (tone NEQ NOT_PRESENT_8BIT) + { + /* + * another DTMF tone has to be sent + */ + p_dtmf->mode = GET_DTMF_MOD (tone); + p_dtmf->key = tone & 0x7f; + CCD_START; + { + MCAST (start, U_START_DTMF); + + cc_build_start_dtmf (p_dtmf->key, start); + for_start_dtmf (start); + } + CCD_END; + + /* On sending a START DTMF message the MS shall start T336 */ + TIMERSTART (T336, T336_VALUE); + + p_dtmf->state = DTMF_SEND_REQUEST; + return; + } + } + p_dtmf->state = DTMF_IDLE; + srv_use_stored_prim (); +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_stop_dtmf_ack | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming stop dtmf ack message. + +*/ + +GLOBAL void cc_stop_dtmf_ack (void) +{ + GET_INSTANCE_DATA; + T_DTMF * p_dtmf; + + TRACE_FUNCTION ("cc_stop_dtmf_ack()"); + + if (cc_dtmf_allowed ()) + { + if (cc_check_error_flag ()) + { + CCD_END; + p_dtmf = &cc_data->dtmf[cc_data->index_ti]; + if (p_dtmf->state EQ DTMF_STOP_REQUEST) + { + if (p_dtmf->mode EQ DTMF_MAN) + { + PALLOC (start, MNCC_START_DTMF_CNF); + start->ti = cc_data->ti; + start->key = NOT_PRESENT_8BIT; + start->cause = MNCC_CAUSE_DTMF_STOP_SUCCESS; + start->dtmf_mod = MNCC_DTMF_MOD_MAN_STOP; + PSENDX (MMI, start); + } + /* Stop T337 */ + TIMERSTOP (TIMER_DTMF); + cc_stop_dtmf (); + } + else + { + /* + * The STOP DTMF ACK message was not expected as we did not sent + * previously a START DTMF request. + */ +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + } + } + } + else + { + /* + * DTMF not allowed in the current state + */ + CCD_END; +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + } +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mncc_facility_req | ++--------------------------------------------------------------------+ + + PURPOSE : Sending of Facility Information by the mobile side. + +*/ + +GLOBAL void cc_mncc_facility_req (T_MNCC_FACILITY_REQ * facility) +{ + GET_INSTANCE_DATA; + + TRACE_FUNCTION ("cc_mncc_facility_req()"); + + if ((cc_data->index_ti = srv_convert_ti (facility->ti)) + EQ NOT_PRESENT_8BIT) + { + PFREE (facility); + return; + } + + switch (cc_data->state[cc_data->index_ti]) + { + case M_CC_CS_19: + PFREE (facility); + break; + + case M_CC_CS_01: + case CS_101: + case CS_261: + srv_store_prim ((T_PRIM *)D2P(facility)); + break; + + default: + CCD_START; + { + MCAST (facility_msg, U_FACILITY); + cc_build_facility (facility, facility_msg); + for_facility (facility_msg); + + EM_CC_FACILITY_TO_THE_NETWORK; + + } + CCD_END; + PFREE (facility); + break; + } +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mncc_modify_req | ++--------------------------------------------------------------------+ + + PURPOSE : Start of a mobile originated in-call modification. + +*/ + +GLOBAL void cc_mncc_modify_req (T_MNCC_MODIFY_REQ * modify) +{ + GET_INSTANCE_DATA; + + TRACE_FUNCTION ("cc_mncc_modify_req()"); + + if ((cc_data->index_ti = srv_convert_ti (modify->ti)) + EQ NOT_PRESENT_8BIT) + { + PFREE (modify); + return; + } + + switch (cc_data->state[cc_data->index_ti]) + { + case M_CC_CS_10: + if (((cc_data->hold_state[cc_data->index_ti] EQ M_CC_HLD_IDLE)) AND + (cc_data->dtmf[cc_data->index_ti].state EQ DTMF_IDLE)) + { + /* + * If no other procedure is running + */ + CCD_START; + { + MCAST (modify_msg, B_MODIFY); + cc_build_modify (modify, modify_msg); + for_modify (modify_msg); + } + CCD_END; + PFREE (modify); + cc_set_state (M_CC_CS_26); + TIMERSTART (T323, T323_VALUE); + + EM_CC_MO_IN_CALL_MODIFICATION; + + } + else + srv_store_prim ((T_PRIM *)D2P(modify)); + break; + + default: + PFREE (modify); + break; + } +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mncc_user_req | ++--------------------------------------------------------------------+ + + PURPOSE : Send user information or congestion control. + +*/ + +GLOBAL void cc_mncc_user_req (T_MNCC_USER_REQ * user) +{ + GET_INSTANCE_DATA; + + TRACE_FUNCTION ("cc_mncc_user_req()"); + + if ((cc_data->index_ti = srv_convert_ti (user->ti)) + EQ NOT_PRESENT_8BIT) + { + PFREE (user); + return; + } + + switch (cc_data->state[cc_data->index_ti]) + { + case M_CC_CS_10: + switch (user->congest_lev) + { + case M_CC_CL_RECEIVER_READY: + case M_CC_CL_RECEIVER_NOT_READY: + /* + * Send Congestion Control + */ + CCD_START; + { + MCAST (cong_ctrl, B_CONGEST_CTRL); + + cc_build_congestion_control (user, cong_ctrl); + for_congestion_control (cong_ctrl); + } + CCD_END; + PFREE (user); + break; + default: + /* + * Send User Information + */ + CCD_START; + { + MCAST (user_msg, B_USER_INFO); + + cc_build_user_information (user, user_msg); + for_user_information (user_msg); + } + CCD_END; + PFREE (user); + break; + } + break; + + case CS_101: + srv_store_prim ((T_PRIM *)D2P(user)); + break; + + default: + PFREE (user); + break; + } +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mncc_hold_req | ++--------------------------------------------------------------------+ + + PURPOSE : Send hold message. + +*/ + +GLOBAL void cc_mncc_hold_req (T_MNCC_HOLD_REQ * hold) +{ + + TRACE_FUNCTION ("cc_mncc_hold_req()"); + +/* Implements Measure# 18 */ + cc_mncc_hold_retrieve_req ((T_PRIM *)D2P(hold)); +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mncc_retrieve_req | ++--------------------------------------------------------------------+ + + PURPOSE : Send retrieve message. + +*/ +GLOBAL void cc_mncc_retrieve_req (T_MNCC_RETRIEVE_REQ * retrieve) +{ + + TRACE_FUNCTION ("cc_mncc_retrieve_req()"); + +/* Implements Measure# 18 */ + cc_mncc_hold_retrieve_req ((T_PRIM *)D2P(retrieve)); +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_call_is_active | ++--------------------------------------------------------------------+ + + PURPOSE : Return TRUE if the respective CC instance is in an active + state, otherwise return FALSE. + +*/ + +LOCAL BOOL cc_call_is_active (UBYTE index_ti) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_call_is_active()"); + + switch (cc_data->state[index_ti]) + { + case M_CC_CS_10: + case M_CC_CS_26: + case CS_101: + case CS_261: + return TRUE; + + default: + return FALSE; + } +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mncc_sync_req | ++--------------------------------------------------------------------+ + + PURPOSE : Processing a MNCC_SYNC_REQ primitive. To be able to + understand some details of this function, see first + GSM 03.84, GSM 04.84 and GSM 11.10 chapters 31.4.1 and 31.4.2. + +*/ + +GLOBAL void cc_mncc_sync_req (T_MNCC_SYNC_REQ * mncc_sync_req) +{ + GET_INSTANCE_DATA; + UBYTE i; + + TRACE_FUNCTION ("cc_mncc_sync_req()"); + + if ((cc_data->index_ti = srv_convert_ti (mncc_sync_req->ti)) + EQ NOT_PRESENT_8BIT) + { + PFREE (mncc_sync_req); + return; + } + + switch (cc_data->state[cc_data->index_ti]) + { + /* + * Note: MPTY and HOLD only has a meaning in the following states, + * in other states these aux states have absolutely no meaning. + */ + case M_CC_CS_10: + case M_CC_CS_26: + case CS_101: + case CS_261: + switch (mncc_sync_req->synccs) + { + case MNCC_SYNCCS_MPTY_EVENT: + + TRACE_EVENT_P2 (" ti = %d, mpty_event = %d", + mncc_sync_req->ti, + mncc_sync_req->mpty_event); + + switch (mncc_sync_req->mpty_event) + { + case MNCC_MPTY_BUILD_SENT: + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i) AND + cc_data->mpty_state[i] EQ M_CC_MPTY_IDLE) + { + cc_data->mpty_state[i] = M_CC_MPTY_REQ; + } + } + break; + + case MNCC_MPTY_BUILD_FAIL: + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i) AND + cc_data->mpty_state[i] EQ M_CC_MPTY_REQ) + { + cc_data->mpty_state[i] = M_CC_MPTY_IDLE; + } + } + break; + + case MNCC_MPTY_BUILD_SUCCESS: + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i)) + { + cc_data->mpty_state[i] = M_CC_MPTY_CALL; + cc_data->hold_state[i] = M_CC_HLD_IDLE; + } + } + break; + + /* -- */ + + case MNCC_MPTY_SPLIT_SENT: + if (cc_data->mpty_state[cc_data->index_ti] EQ M_CC_MPTY_CALL) + { + cc_data->mpty_state[cc_data->index_ti] = M_CC_MPTY_SPLIT; + } + break; + + case MNCC_MPTY_SPLIT_FAIL: + if (cc_data->mpty_state[cc_data->index_ti] EQ M_CC_MPTY_SPLIT) + { + cc_data->mpty_state[cc_data->index_ti] = M_CC_MPTY_CALL; + } + break; + + case MNCC_MPTY_SPLIT_SUCCESS: + cc_data->mpty_state[cc_data->index_ti] = M_CC_MPTY_IDLE; + cc_data->hold_state[cc_data->index_ti] = M_CC_HLD_IDLE; + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i) AND + cc_data->mpty_state[i] NEQ M_CC_MPTY_IDLE) + { + cc_data->hold_state[i] = M_CC_HLD_CALL_HELD; + } + } + break; + + /* -- */ + + case MNCC_MPTY_HOLD_SENT: + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i) AND + cc_data->mpty_state[i] NEQ M_CC_MPTY_IDLE) + { + cc_data->hold_state[i] = M_CC_HLD_HOLD_REQ; + } + } + break; + + case MNCC_MPTY_HOLD_FAIL: + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i) AND + cc_data->mpty_state[i] NEQ M_CC_MPTY_IDLE) + { + cc_data->hold_state[i] = M_CC_HLD_IDLE; + } + } + break; + + case MNCC_MPTY_HOLD_SUCCESS: + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i) AND + cc_data->mpty_state[i] NEQ M_CC_MPTY_IDLE) + { + cc_data->hold_state[i] = M_CC_HLD_CALL_HELD; + } + } + break; + + /* -- */ + + case MNCC_MPTY_RETRIEVE_SENT: + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i) AND + cc_data->mpty_state[i] NEQ M_CC_MPTY_IDLE) + { + cc_data->hold_state[i] = M_CC_HLD_RETRIEVE_REQ; + } + } + break; + + case MNCC_MPTY_RETRIEVE_FAIL: + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i) AND + cc_data->mpty_state[i] NEQ M_CC_MPTY_IDLE) + { + cc_data->hold_state[i] = M_CC_HLD_CALL_HELD; + } + } + break; + + case MNCC_MPTY_RETRIEVE_SUCCESS: + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i) AND + cc_data->mpty_state[i] NEQ M_CC_MPTY_IDLE) + { + cc_data->hold_state[i] = M_CC_HLD_IDLE; + } + } + break; + + /* -- */ + + default: + TRACE_ERROR ("Illegal MPTY event"); + break; + } /* switch (mncc_sync_req->mpty_event) */ + break; + + default: + TRACE_ERROR ("Illegal SYNCCS"); + } /* switch (mncc_sync_req->synccs) */ + break; + + default: + break; /* Ignore the event */ + } /* switch (cc_data->state[cc_data->index_ti]) */ + +#ifndef NTRACE + for (i = 0; i < MAX_CC_CALLS; i++) + { + if (cc_call_is_active(i)) + { + TRACE_EVENT_P4 (" hold[%d] = %d, mpty[%d] = %d", + cc_data->stored_ti_values[i], + cc_data->hold_state[i], + cc_data->stored_ti_values[i], + cc_data->mpty_state[i]); + } + } +#endif /* #ifndef NTRACE */ + + PFREE (mncc_sync_req); +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mncc_status_res | ++--------------------------------------------------------------------+ + + PURPOSE : Processing a MNCC_STATUS_RES primitive. There is an + outstanding STATUS message which still has to be sent to + the network after having received a STATUS ENQUIRY in U10. + +*/ + +GLOBAL void cc_mncc_status_res (T_MNCC_STATUS_RES * mncc_status_res) +{ + GET_INSTANCE_DATA; + + TRACE_FUNCTION ("cc_mncc_status_res()"); + + if ((cc_data->index_ti = srv_convert_ti (mncc_status_res->ti)) + EQ NOT_PRESENT_8BIT) + { + PFREE (mncc_status_res); + return; + } + + switch (cc_data->state[cc_data->index_ti]) + { + case M_CC_CS_01: /* MM connection pending */ + case CS_101: /* No network connection, reestablishment in progress */ + case CS_261: + break; + + default: +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_STATUS_ENQUIRY); + break; + } + + PFREE (mncc_status_res); +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_facility | ++--------------------------------------------------------------------+ + + PURPOSE : Processing of an incoming facility message. + +*/ + +GLOBAL void cc_facility (T_D_FACILITY * facility) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_facility()"); + + /* + * A facility message can be received in every state where CC has a + * MM connection, no need to check states here. + */ + if (cc_check_error_flag ()) + { + cc_build_facility_ind (MNCC_FAC_IN_FACILITY, TRUE, &facility->facility); + CCD_END; + } + + EM_CC_FACILITY_FROM_THE_NETWORK; + +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_hold_ack | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming hold ack message. + +*/ + +GLOBAL void cc_hold_ack (void) +{ + GET_INSTANCE_DATA; + CCD_END; + + TRACE_FUNCTION ("cc_hold_ack()"); + + switch (cc_data->state[cc_data->index_ti]) + { + /* + * CS_0 is handled by the formatter + */ + case M_CC_CS_10: + if (cc_check_error_flag ()) + { + if (cc_data->hold_state[cc_data->index_ti] EQ M_CC_HLD_HOLD_REQ) + { + PALLOC (hold_cnf, MNCC_HOLD_CNF); + + cc_data->hold_state[cc_data->index_ti] = M_CC_HLD_CALL_HELD; + hold_cnf->ti = cc_data->ti; + hold_cnf->cause = MNCC_CAUSE_HOLD_SUCCESS; + PSENDX (MMI, hold_cnf); + + EM_CC_CALL_HOLD_ACKNOWLEDGE; + + } + else + { +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + } + } + break; + + default: +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + break; + } +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_hold_rej | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming hold rej message. + +*/ + +GLOBAL void cc_hold_rej (T_D_HOLD_REJ * hold_rej) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_hold_rej()"); + + switch (cc_data->state[cc_data->index_ti]) + { + /* + * CS_0 is handled by the formatter + */ + case M_CC_CS_10: + if (cc_data->hold_state[cc_data->index_ti] EQ M_CC_HLD_HOLD_REQ) + { + PALLOC (hold_cnf, MNCC_HOLD_CNF); + + cc_data->hold_state[cc_data->index_ti] = M_CC_HLD_IDLE; + hold_cnf->ti = cc_data->ti; + + /* + * It is possible for the network to send a REJ without a Cause IE. + * This causes the decoder to flag a Madatory IE error. According to + * 04.08 Sec: 8.5.3.e, the REJ should still be managed as if a correctly + * formatted REJ had been received. + */ + if (!hold_rej->cc_cause.v_cause) + { + hold_cnf->cause = MNCC_CAUSE_NO_NET_CAUSE; + } + else + { + hold_cnf->cause = CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_NET, + MNCC_CC_ORIGINATING_ENTITY, + hold_rej->cc_cause.cause); + } + PSENDX (MMI, hold_cnf); + srv_use_stored_prim (); + + EM_CC_CALL_HOLD_REJECT; + + CCD_END; + } + else + { + CCD_END; +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + } + break; + + default: + CCD_END; +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + break; + } +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_retrieve_ack | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming retrieve ack message. + +*/ + +GLOBAL void cc_retrieve_ack (void) +{ + GET_INSTANCE_DATA; + + TRACE_FUNCTION ("cc_retrieve_ack()"); + + switch (cc_data->state[cc_data->index_ti]) + { + /* + * CS_0 is handled by the formatter + */ + case M_CC_CS_10: + if (cc_check_error_flag ()) + { + CCD_END; + if (cc_data->hold_state[cc_data->index_ti] EQ M_CC_HLD_RETRIEVE_REQ) + { + PALLOC (retrieve_cnf, MNCC_RETRIEVE_CNF); + + cc_data->hold_state[cc_data->index_ti] = M_CC_HLD_IDLE; + retrieve_cnf->ti = cc_data->ti; + retrieve_cnf->cause = MNCC_CAUSE_RETRIEVE_SUCCESS; + PSENDX (MMI, retrieve_cnf); + + EM_CC_CALL_RETRIEVE_ACKNOWLEDGE; + + } + else + { +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + } + } + break; + + default: + CCD_END; +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + break; + } +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_retrieve_rej | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming retrieve rej message. + +*/ + +GLOBAL void cc_retrieve_rej (T_D_RETRIEVE_REJ * retrieve_rej) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_retrieve_rej()"); + + switch (cc_data->state[cc_data->index_ti]) + { + /* + * CS_0 is handled by the formatter + */ + case M_CC_CS_10: + if (cc_data->hold_state[cc_data->index_ti] EQ M_CC_HLD_RETRIEVE_REQ) + { + PALLOC (retrieve_cnf, MNCC_RETRIEVE_CNF); + + cc_data->hold_state[cc_data->index_ti] = M_CC_HLD_CALL_HELD; + retrieve_cnf->ti = cc_data->ti; + + /* + * It is possible for the network to send a REJ without a Cause IE. + * This causes the decoder to flag a Madatory IE error. According to + * 04.08 Sec: 8.5.3.e, the REJ should still be managed as if a correctly + * formatted REJ had been received. + */ + if (!retrieve_rej->cc_cause.v_cause) + { + retrieve_cnf->cause = MNCC_CAUSE_NO_NET_CAUSE; + } + else + { + retrieve_cnf->cause = CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_NET, + MNCC_CC_ORIGINATING_ENTITY, + retrieve_rej->cc_cause.cause); + } + PSENDX (MMI, retrieve_cnf); + srv_use_stored_prim (); + + EM_CC_CALL_RETRIEVE_REJECT; + + CCD_END; + } + else + { + CCD_END; +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + } + break; + + default: + CCD_END; +/* Implements Measure# 3 and streamline encoding */ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + break; + } +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_congestion_control | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming congestion control message. + +*/ + +GLOBAL void cc_congestion_control (T_B_CONGEST_CTRL * cong) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_congestion_control()"); + + switch (cc_data->state[cc_data->index_ti]) + { + /* + * CS_0 is handled by the formatter + */ + case M_CC_CS_10: + if (cc_check_error_flag ()) + { + PALLOC (user, MNCC_USER_IND); + + cc_build_user_ind_from_cong (user, cong); + PSENDX (MMI, user); + CCD_END; + } + break; + + default: + CCD_END; +/* Implements Measure# 3 and streamline encoding*/ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + break; + } +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_user_information | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming user information message. + +*/ + +GLOBAL void cc_user_information ( T_B_USER_INFO * user) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_user_information()"); + + switch (cc_data->state[cc_data->index_ti]) + { + /* + * CS_0 is handled by the formatter + */ + case M_CC_CS_10: + if (cc_check_error_flag ()) + { + PALLOC (user_ind, MNCC_USER_IND); + + cc_build_user_ind_from_user (user_ind, user); + CCD_END; + PSENDX (MMI, user_ind); + + EM_CC_USER_TO_USER_DATA_RECEIVED; + + } + break; + + default: + CCD_END; +/* Implements Measure# 4 and streamline encoding*/ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + break; + } +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_modify | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming modify message. + +*/ + +GLOBAL void cc_modify (T_B_MODIFY * modify) +{ + GET_INSTANCE_DATA; + + TRACE_FUNCTION ("cc_modify()"); + + switch (cc_data->state[cc_data->index_ti]) + { + /* + * CS_0 is handled by the formatter + */ + case M_CC_CS_10: + if (cc_check_error_flag ()) + { + switch (cc_data->neg_ri) + { + case M_CC_REPEAT_CIRCULAR: + if (cc_data->active_service EQ cc_data->neg_serv1) + { + if (cc_bcs_compatible (&modify->bearer_cap, + &cc_data->neg_bc2, TRUE) EQ TRUE) + { + CCD_END; + cc_mod_complete (); + } + else + { + CCD_END; + cc_mod_reject (); + } + } + else + { + if (cc_bcs_compatible (&modify->bearer_cap, + &cc_data->neg_bc1, TRUE) EQ TRUE) + { + CCD_END; + cc_mod_complete (); + } + else + { + CCD_END; + cc_mod_reject (); + } + } + break; +#ifndef REL99 + case M_CC_REPEAT_SEQUENTIAL: + if (cc_data->active_service EQ cc_data->neg_serv1) + { + if (cc_bcs_compatible (&modify->bearer_cap, + &cc_data->neg_bc2, TRUE) EQ TRUE) + { + CCD_END; + cc_mod_complete (); + } + else + { + CCD_END; + cc_mod_reject (); + } + } + else + { + CCD_END; + cc_mod_reject (); + } + break; +#endif /* #ifndef REL99 */ + default: + CCD_END; + cc_mod_reject (); + break; + } + } + break; + + default: + CCD_END; +/* Implements Measure# 5 and streamline encoding*/ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + break; + } +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mod_reject | ++--------------------------------------------------------------------+ + + PURPOSE : Negative end of a mobile terminated in-call modification. + +*/ + +GLOBAL void cc_mod_reject (void) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_mod_reject()"); + + CCD_START; + { + MCAST (modify_rej, B_MODIFY_REJ); + + + cc_build_modify_reject (modify_rej, + CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_MS, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_BEARER_CAP_AUTHORIZ)); + for_modify_reject (modify_rej); + } + + EM_CC_MT_IN_CALL_MODIFICATION_FAILED; + + CCD_END; +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mod_complete | ++--------------------------------------------------------------------+ + + PURPOSE : Positive end of a mobile terminated in-call modification. + +*/ + +GLOBAL void cc_mod_complete (void) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_mod_complete()"); + + CCD_START; + { + MCAST (modify_com, B_MODIFY_COMP); + PALLOC (mod_ind, MNCC_MODIFY_IND); + + + if (cc_data->active_service EQ cc_data->neg_serv1) + cc_data->active_service = cc_data->neg_serv2; + else + cc_data->active_service = cc_data->neg_serv1; + + mod_ind->ti = cc_data->ti; + mod_ind->serv = cc_data->active_service; + PSENDX (MMI, mod_ind); + + EM_CC_MT_IN_CALL_MODIFICATION_PASSED; + + cc_build_modify_complete (modify_com); + for_modify_complete (modify_com); + } + CCD_END; +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_modify_complete | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming modify complete message. + +*/ + +GLOBAL void cc_modify_complete ( T_B_MODIFY_COMP * mod_com) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_modify_complete()"); + + switch (cc_data->state[cc_data->index_ti]) + { + /* + * CS_0 is handled by the formatter + */ + case M_CC_CS_26: + if (cc_check_error_flag ()) + { + if (cc_data->new_itc EQ mod_com->bearer_cap.trans_cap) + { + PALLOC (mod_cnf, MNCC_MODIFY_CNF); + + TIMERSTOP (TIMER_CC); + if (cc_data->active_service EQ cc_data->serv1) + cc_data->active_service = cc_data->serv2; + else + cc_data->active_service = cc_data->serv1; + mod_cnf->ti = cc_data->ti; + mod_cnf->cause = MNCC_CAUSE_MODIFY_SUCCESS; + /* Setting raw_cause to empty as we are not sending any cause from network*/ + mod_cnf->c_raw_cause = 0; + + EM_CC_MO_IN_CALL_MODIFICATION_PASSED; + + PSENDX (MMI, mod_cnf); + cc_set_state (M_CC_CS_10); + } + CCD_END; + } + break; + + default: + CCD_END; +/* Implements Measure# 6 and streamline encoding*/ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + break; + } +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_modify_reject | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming modify reject message. + +*/ + +GLOBAL void cc_modify_reject (T_B_MODIFY_REJ * mod_rej) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_modify_reject()"); + + switch (cc_data->state[cc_data->index_ti]) + { + /* + * CS_0 is handled by the formatter + */ + case M_CC_CS_26: + if (cc_check_error_flag ()) + { + if (cc_data->old_itc EQ mod_rej->bearer_cap.trans_cap) + { + PALLOC (mod_cnf, MNCC_MODIFY_CNF); + + TIMERSTOP (TIMER_CC); + mod_cnf->ti = cc_data->ti; + /* + * cause IE is mandatory and the check for presence has been done + * already thus there is no need to check for validity of cause IE + * here anymore + */ + mod_cnf->cause = CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_NET, + MNCC_CC_ORIGINATING_ENTITY, + mod_rej->cc_cause.cause); + mod_cnf->c_raw_cause = cc_build_cause (&mod_rej->cc_cause, + mod_cnf->raw_cause); + PSENDX (MMI, mod_cnf); + cc_set_state (M_CC_CS_10); + } + + EM_CC_MO_IN_CALL_MODIFICATION_FAILED; + + CCD_END; + } + break; + + default: + CCD_END; +/* Implements Measure# 7 and streamline encoding*/ + cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT); + break; + } +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_status | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming status message. + +*/ + +GLOBAL void cc_status (T_B_STATUS * status) +{ + GET_INSTANCE_DATA; + TRACE_FUNCTION ("cc_status()"); + + /* The cause is in STATUS a mandatory IE (given intact message) */ + TRACE_EVENT_P1 ("STATUS cause: %02x", status->cc_cause.cause); + + switch (cc_data->state[cc_data->index_ti]) + { + case M_CC_CS_0: + CCD_END; + if (status->call_state.state NEQ M_CC_CS_0) + { + CCD_START; + { + MCAST (rel_com, U_RELEASE_COMP); + + cc_build_release_complete (rel_com, + CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_MS, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_MESSAGE_INCOMPAT)); + for_release_complete (rel_com); + } + CCD_END; + } + for_rel_req (); + break; + + case M_CC_CS_1: + case M_CC_CS_3: + case M_CC_CS_4: + case M_CC_CS_6: + case M_CC_CS_7: + case M_CC_CS_8: + case M_CC_CS_9: + case M_CC_CS_10: + case M_CC_CS_26: + if (cc_check_error_flag ()) + { + /* check for incompatible state */ + if (status->call_state.state NEQ cc_data->state[cc_data->index_ti]) + { + PALLOC (rel_ind, MNCC_RELEASE_IND); + + cc_reset_dtmf (); // China change HM 11.07.00 + + TIMERSTOP (TIMER_CC); + + rel_ind->ti = cc_data->ti; + + rel_ind->cause = CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_MS, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_MESSAGE_INCOMPAT); + rel_ind->c_raw_cause = 0; + PSENDX (MMI, rel_ind); + + CCD_END; + CCD_START; + { + MCAST (rel_com, U_RELEASE_COMP); + + cc_build_release_complete (rel_com, + CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_MS, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_MESSAGE_INCOMPAT)); + for_release_complete (rel_com); + } + CCD_END; + for_rel_req (); + cc_set_state (M_CC_CS_0); + } + else + /* + * compatible, perform checks/ actions of 04.08, ch. 5.5.3.2.2; + * Condat action (option!) is to initiate normal call clearing + * (with DISCONNECT) + */ + { + if ((status->cc_cause.cause >= M_CC_CAUSE_INCORRECT_MESSAGE) + AND + (status->cc_cause.cause <= M_CC_CAUSE_COND_INFO_ELEM)) + { + /* + * Block entered for + * CAUSE_INCORRECT_MESSAGE, CAUSE_INVALID_MAND_INFO, + * CAUSE_MESSAGE_TYPE_NOT_IMPLEM, CAUSE_MESSAGE_TYPE_INCOMPAT, + * CAUSE_INFO_ELEM_NOT_IMPLEM, CAUSE_COND_INFO_ELEM. (0x5f..0x64) + */ + if ((cc_data->state[cc_data->index_ti] EQ M_CC_CS_10) AND + (cc_data->hold_state[cc_data->index_ti] EQ M_CC_HLD_HOLD_REQ)) + { + /* + * Compatible state, last CC message was a hold request which is + * not supported by the network. Handled like HOLD REJECT. + */ + PALLOC (hold_cnf, MNCC_HOLD_CNF); /* T_MNCC_HOLD_CNF */ + cc_data->hold_state[cc_data->index_ti] = M_CC_HLD_IDLE; + hold_cnf->ti = cc_data->ti; + hold_cnf->cause = CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_NET, + MNCC_CC_ORIGINATING_ENTITY, + status->cc_cause.cause); + PSENDX (MMI, hold_cnf); + CCD_END; + srv_use_stored_prim (); + } + else if (status->cc_cause.cause NEQ M_CC_CAUSE_INFO_ELEM_NOT_IMPLEM) + { + /* + * Compatible state, special condition for HOLD REQUEST not met. + * The network is also not complaining about an optional + * information element which can be simply ignored. + * Disconnect the call. + */ + PALLOC (disc_ind, MNCC_DISCONNECT_IND); + + TIMERSTOP (TIMER_CC); + + disc_ind->ti = cc_data->ti; + disc_ind->cause = CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_NET, + MNCC_CC_ORIGINATING_ENTITY, + status->cc_cause.cause); + disc_ind->c_raw_cause = cc_build_cause (&status->cc_cause, + disc_ind->raw_cause); + disc_ind->diagnostic = NOT_PRESENT_8BIT; + disc_ind->progress_desc = MNCC_PROG_NOT_PRES; + PSENDX (MMI, disc_ind); + + CCD_END; + CCD_START; + { + MCAST (disconnect, U_DISCONNECT); + + cc_build_disconnect (disconnect, + CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_MS, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_CALL_CLEAR), + NULL, MNCC_SS_VER_NOT_PRES); + for_disconnect (disconnect); + } + TIMERSTART (T305, T305_VALUE); + cc_set_state (M_CC_CS_11); + } + } + else + { + /* + * STATUS message but neither incompatible state nor indicating + * incorrect message / IE; check if we received a STATUS with cause + * "message not compatible with protocol state". GSM 04.08 does not + * define what to do and also does not define that this case has to + * be handled at all; + * Condat (HM) decided to "clear DTMF" if it was running to try to + * recover from the misaligned states scenario. + */ + T_DTMF *p_dtmf; + + p_dtmf = &cc_data->dtmf[cc_data->index_ti]; + if ((p_dtmf->state EQ DTMF_SEND_REQUEST) AND + (status->cc_cause.cause EQ M_CC_CAUSE_MESSAGE_INCOMPAT)) + { + /* Send negative acknowledge for DTMF send request to MMI */ + PALLOC (mncc_start_dtmf_cnf, MNCC_START_DTMF_CNF); + mncc_start_dtmf_cnf->ti = cc_data->ti; + mncc_start_dtmf_cnf->key = NOT_PRESENT_8BIT; + mncc_start_dtmf_cnf->dtmf_mod = NOT_PRESENT_8BIT; + mncc_start_dtmf_cnf->cause = CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_NET, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_MESSAGE_INCOMPAT); + PSENDX (MMI, mncc_start_dtmf_cnf); + } + + /* Bring screwed up network back to work */ + for_stop_dtmf (); + + /* Reset screwed up DTMF state machine */ + p_dtmf->state = DTMF_IDLE; + p_dtmf->read = 0; + p_dtmf->write = 0; + } + CCD_END; + } + } + break; + + case M_CC_CS_11: + case M_CC_CS_12: + if (cc_check_error_flag ()) + { + if (status->call_state.state NEQ cc_data->state[cc_data->index_ti]) + { + /* + * STATUS message with incompatible state + * On receipt of a STATUS message reporting an incompatible call + * control state, the receiving entity shall clear the call by + * sending a RELEASE COMPLETE message with cause # 101 "message + * not compatible with protocol state". The reported call control + * state is incompatible if the combination of call control states + * at the sender and receiver side cannot occur, do not match or cannot + * be aligned by actions of the receiver; the exact definition is + * implementation dependent. [04.08 clause 5.5.3.2.1] + */ + cc_reset_dtmf (); + + TIMERSTOP (TIMER_CC); + + /* Send MNCC_RELEASE_IND to MMI */ + { + PALLOC (rel_ind, MNCC_RELEASE_IND); /* T_MNCC_RELEASE_IND */ + rel_ind->ti = cc_data->ti; + rel_ind->cause = CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_MS, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_MESSAGE_INCOMPAT); + rel_ind->c_raw_cause = 0; + PSENDX (MMI, rel_ind); + } + + CCD_END; + CCD_START; + { + MCAST (rel_com, U_RELEASE_COMP); /* T_U_RELEASE_COMP */ + cc_build_release_complete (rel_com, + CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_MS, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_MESSAGE_INCOMPAT)); + for_release_complete (rel_com); + for_rel_req (); + cc_set_state (M_CC_CS_0); + } + } + CCD_END; + } + break; + + case M_CC_CS_19: + if (cc_check_error_flag ()) + { + if (status->call_state.state NEQ cc_data->state[cc_data->index_ti]) + { + TIMERSTOP (TIMER_CC); + + cc_reset_dtmf (); + + { + PALLOC (rel_cnf, MNCC_RELEASE_CNF); /* T_MNCC_RELEASE_CNF */ + rel_cnf->ti = cc_data->ti; + rel_cnf->cause = CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_MS, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_MESSAGE_INCOMPAT); + /* Setting raw_cause to empty as this is a local release + * of MM connection,CC is not receiving any cause value + * from Network + */ + rel_cnf->c_raw_cause = 0; + PSENDX (MMI, rel_cnf); + } + + CCD_END; + CCD_START; + { + MCAST (rel_com, U_RELEASE_COMP); /* T_U_RELEASE_COMP */ + cc_build_release_complete (rel_com, + CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_MS, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_MESSAGE_INCOMPAT)); + for_release_complete (rel_com); + for_rel_req (); + cc_set_state (M_CC_CS_0); + } + } + CCD_END; + } + break; + + default: + CCD_END; + break; + } + + EM_CC_STATUS_RECEIVED; + +} + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_status_enquiry | ++--------------------------------------------------------------------+ + + PURPOSE : Processing an incoming status enquiry message. + +*/ + +GLOBAL void cc_status_enquiry (void) +{ + GET_INSTANCE_DATA; + + TRACE_FUNCTION ("cc_status_enquiry()"); + + /* + * CS_0 is handled by the formatter + */ + switch (cc_data->state[cc_data->index_ti]) + { + case M_CC_CS_10: + /* + * Ensure synchronization of auxiliary states with ACI. + */ + if (cc_check_error_flag ()) + { + CCD_END; + { + PALLOC (mncc_status_ind, MNCC_STATUS_IND); + mncc_status_ind->ti = cc_data->ti; + PSENDX (MMI, mncc_status_ind); + } + + EM_CC_STATUS_ENQUIRY_RECEIVED; + + } + break; + + default: + /* + * No auxiliary states in non-active states. Immediate response is safe. + */ + if (cc_check_error_flag ()) + { + CCD_END; + /* EM call moved above cc_send_status should not have any impact */ + EM_CC_STATUS_ENQUIRY_RECEIVED; + +/* Implements Measure# 7 and streamline encoding*/ + cc_send_status (M_CC_CAUSE_STATUS_ENQUIRY); + } + break; + } +} + + +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_unknown_message | ++--------------------------------------------------------------------+ + + PURPOSE : Processing of an incoming unknown message. + +*/ + +GLOBAL void cc_unknown_message (void) +{ + + CCD_END; + CCD_START; + { + MCAST (status, B_STATUS); + + TRACE_FUNCTION ("cc_unknown_message()"); + + cc_build_status (status, + CAUSE_MAKE(DEFBY_STD, + ORIGSIDE_MS, + MNCC_CC_ORIGINATING_ENTITY, + M_CC_CAUSE_MESSAGE_TYPE_NOT_IMPLEM)); + for_status (status); + } + CCD_END; +} + +/* Implements Measure# 18 */ +/* ++--------------------------------------------------------------------+ +| PROJECT : GSM-PS (6147) MODULE : CC_ACT | +| STATE : code ROUTINE : cc_mncc_hold_retrieve_req | ++--------------------------------------------------------------------+ + + PURPOSE : Send hold REQ/retrieve REQ. + +*/ + +LOCAL void cc_mncc_hold_retrieve_req (T_PRIM * prim) +{ + GET_INSTANCE_DATA; + UBYTE ti; + + TRACE_FUNCTION ("cc_mncc_hold_retrieve_req()"); + + if(prim->custom.opc EQ MNCC_HOLD_REQ) + { + ti = ((T_MNCC_HOLD_REQ *)P2D(prim))->ti; + } + else + { + ti = ((T_MNCC_RETRIEVE_REQ *)P2D(prim))->ti; + } + if ((cc_data->index_ti = srv_convert_ti (ti)) EQ NOT_PRESENT_8BIT) + { + PFREE (P2D(prim)); + return; + } + + switch (cc_data->state[cc_data->index_ti]) + { + case M_CC_CS_10: + if(prim->custom.opc EQ MNCC_HOLD_REQ) + { + /* We should think about storing the hold request + until DTMF idle state reached. ... + This causes some other changes, we have to add some + calls to serv_use_stored_prim() at some places after + state transition of the DTMF state machine to DTMF idle.*/ + cc_data->hold_state[cc_data->index_ti] = M_CC_HLD_HOLD_REQ; + for_hold (); + EM_CC_CALL_HOLD; + } + else + { + cc_data->hold_state[cc_data->index_ti] = M_CC_HLD_RETRIEVE_REQ; + for_retrieve (); + EM_CC_CALL_RETRIEVE; + } + PFREE (P2D(prim)); + + break; + + case CS_101: + case M_CC_CS_26: + case CS_261: + srv_store_prim (prim); + break; + + default: + PFREE (P2D(prim)); + break; + } +} + +#endif