FreeCalypso > hg > fc-magnetite
view src/g23m-gsm/rr/rr_datf.c @ 288:dd3374eac8a3
AT@VPATH setting implemented
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 27 Aug 2017 05:53:20 +0000 |
parents | 27a4235405c6 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : | Modul : +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : This module defines the functions for the data transfer | capability of the module Radio Resource. +----------------------------------------------------------------------------- */ #ifndef RR_DATF_C #define RR_DATF_C #define ENTITY_RR /*==== INCLUDES ===================================================*/ #include <string.h> #include <stdlib.h> #include <stddef.h> /* offsetof */ #include "typedefs.h" #include "pcm.h" #include "pconst.cdg" #include "mconst.cdg" #include "message.h" #include "ccdapi.h" #include "vsi.h" #include "custom.h" #include "gsm.h" #include "prim.h" #include "cnf_rr.h" #include "tok.h" #include "rr.h" #include "rr_em.h" /*==== EXPORT =====================================================*/ /*==== PRIVATE ====================================================*/ static void dat_fill_mobile_identity (USHORT fill_type, T_mob_ident *moid); static BOOL dat_eplmn_equal_req (const UBYTE *mcc, const UBYTE *mnc); static void dat_get_background_and_bits (UBYTE *background, UBYTE *bits); static UBYTE dat_get_burst (UBYTE background, UBYTE bits); static UBYTE dat_get_delta (UBYTE i); static UBYTE dat_get_ncell_pos (USHORT channel); static BOOL dat_hplmn_country (const UBYTE *mcc); static SHORT dat_imsi_mod_1000 (void); static SHORT dat_no_of_paging_blocks (UBYTE index); static BOOL dat_owner_of_auth_0_to_9 (void); static BOOL dat_owner_of_auth_11_to_15 (void); static void dat_send_random_bursts (void); typedef struct CODE_TABLE { USHORT cause; UBYTE last_channel; UBYTE neci_flag; UBYTE channel_needed; UBYTE ms_capability; UBYTE tch_f_needed; UBYTE background; UBYTE bits; } CODE_TABLE ; typedef struct CONVER_TXINTEGER { USHORT t; USHORT s_non_combined; USHORT s_combined; } CONVERT_TXINTEGER; /*==== VARIABLES ==================================================*/ /*==== FUNCTIONS ==================================================*/ /* * ------------------------------------------------------------------- * Procedures * ------------------------------------------------------------------- */ /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_access_allowed | +--------------------------------------------------------------------+ PURPOSE : The function decides whether the access to the network is allowed or not. (GSM 4.18, chapter 3.3.1.1.1 Permission to access the network). */ GLOBAL BOOL dat_access_allowed (USHORT establish_cause) { GET_INSTANCE_DATA; BOOL result = TRUE; TRACE_FUNCTION ("dat_access_allowed()"); #if defined (_SIMULATION_) TRACE_EVENT_P1 ("ACC CLASS BCCH = %4x", rr_data->nc_data[SC_INDEX].rach.ac); TRACE_EVENT_P1 ("ACC CLASS SIM = %4x", rr_data->ms_data.access_classes); #endif if (establish_cause EQ ESTCS_EMERGENCY_CALL) { /* * if it is an emergency call the corresponding flag * in the random access control parameters must be set */ if (rr_data->nc_data[SC_INDEX].rach.ac & 0x0400) result = FALSE; /* * or the MS must be member of one of the special classes * defined on the SIM card. */ if (result EQ FALSE) { result = dat_owner_of_auth_11_to_15 (); } } else { /* * for non-ememrgency calls */ /* * Normally, the whole check here should not be necessary as MM * should know about limited service condition and not try to * update in automatic mode or to establish a non-emergency CM service. * So the check here is superflous, but if it catches, MM has a problem * as it will think the cell is temporary barred and will wait for the * barr state to change, not indicating limited service to the MMI under * certain circumstances. It seems so that here something was fixed at * the wrong place. * The old condition was: if (dat_forbidden_lai_check (SC_INDEX)) */ if( (establish_cause EQ ESTCS_LOCATION_UPDATING) AND ((rr_data->ms_data.operation_mode & 0x40) EQ 0x40) ) { /* * Do not barr access for MM procedure establishment if we are in manual * mode. This was previously bypassed within dat_forbidden_lai_check() * function but was leading to incorrect cell reselection whilst RR * was in manual. * If MM wants to perform a LU at this place it means that user manually * selected this network and is then allowed to attempt registration. If * we reseleted on a LAC forbidden for provision of regional service, MM * is switched to limited service so no normal LU will be triggered. */ if (dat_owner_of_auth_0_to_9 ()) result = TRUE; else result = dat_owner_of_auth_11_to_15 (); } else if ( rr_data->ms_data.rr_service EQ LIMITED_SERVICE) { /* * RR is in limited service. * Only emergency calls are allowed in this state */ result = FALSE; } else if ( dat_forb_lai_check (SC_INDEX) AND dat_roam_forb_lai_check (SC_INDEX) ) { /* * if RR is not inside of a forbidden location area, * the MS must be member of one of the normal or one * of the special classes stored on the SIM card. */ if (dat_owner_of_auth_0_to_9 ()) result = TRUE; else result = dat_owner_of_auth_11_to_15 (); } else { /* * if RR is inside of a forbidden location area * no normal calls are allowed */ TRACE_ERROR ("Unexpected, MM doesn't know its service state."); result = FALSE; } } return (result); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_calc_downlink_timeout | +--------------------------------------------------------------------+ PURPOSE : The downlink signalling failure criterion is based on the downlink signalling failure counter DSC. When the MS camps on a cell, DSC shall be initialized to a value equal to the nearest integer to 90/N where N is the BS_PA_MFRMS parameter for that cell (GSM 5.08, chapter 6.5 Downlink Signalling Failure). */ GLOBAL UBYTE dat_calc_downlink_timeout (UBYTE index) { GET_INSTANCE_DATA; UBYTE divisor; UBYTE dl=0; TRACE_FUNCTION ("dat_calc_downlink_timeout()"); /* * The stored value for BS_PA_MFRMS is in air-interface coding. * To get the real value a value of 2 must be added */ divisor = rr_data->nc_data[index].control_descr.bs_pa_mfrms + 2; /* * calculate the initial value for the downlink signalling counter. */ TRACE_ASSERT(divisor NEQ 0); if(divisor NEQ 0) { dl = 90 / divisor; } /* * correct rounding failures * * BS_PA_MFRMS = 2 -> 90/2 = 45 * 3 -> 90/3 = 30 * 4 -> 90/4 = 22.5 -> 23 * 5 -> 90/5 = 18 * 6 -> 90/6 = 15 * 7 -> 90/7 = 12.85 -> 13 * 8 -> 90/8 = 11.25 * 9 -> 90/9 = 10 */ if (divisor EQ 4 OR divisor EQ 7) { dl++; } return (dl); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_calc_paging_group | +--------------------------------------------------------------------+ PURPOSE : Calculation of paging group is described in GSM 5.02, chapter 6.5.2. PAGING_GROUP (0 .. N-1) = ((IMSI mod 1000) mod (BS_CC_CHANS x N)) mod N where N = number of paging blocks "available" on one CCCH = (number of paging blocks "available" in a 51-multiframe on one CCCH) x BS_PA_MFRMS. IMSI = International Mobile Subscriber Identity, as defined in GSM 03.03. mod = Modulo. */ GLOBAL UBYTE dat_calc_paging_group (UBYTE index) { GET_INSTANCE_DATA; /* * calculation of the number of paging blocks */ SHORT n = dat_no_of_paging_blocks (index); /* * calculation of IMSI modulo 1000 */ SHORT a = dat_imsi_mod_1000 (); /* * calculation of BS_CC_CHANS * N (GSM 5.02 section 3.3.2.3) */ SHORT b = ((rr_data->nc_data[index].control_descr.ccch_conf / 2) + 1) * n; TRACE_FUNCTION ("dat_calc_paging_group()"); /* * calculation of the paging group */ return ((UBYTE) ((a % b) % n)); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_calc_tn | +--------------------------------------------------------------------+ PURPOSE : Determination of the timeslot of the paging block for the MS in idle mode is described in GSM 5.02, chapter 6.5.2 The formula for calculation of the CCCH group must be used. The dependency between timeslot and CCCH group is tn = 2 * CCCH_GROUP CCCH_GROUP (0 .. BS_CC_CHANS-1) = ((IMSI mod 1000) mod (BS_CC_CHANS x N)) div N where N = number of paging blocks "available" on one CCCH = (number of paging blocks "available" in a 51-multiframe on one CCCH) x BS_PA_MFRMS. IMSI = International Mobile Subscriber Identity, as defined in GSM 03.03. mod = Modulo. div = Integer division. */ GLOBAL UBYTE dat_calc_tn (UBYTE index) { GET_INSTANCE_DATA; /* * calculate the number of paging blocks */ SHORT n = dat_no_of_paging_blocks (index); /* * calculate IMSI modulo 1000 */ SHORT a = dat_imsi_mod_1000 (); /* * calculate BS_CC_CHANS * N (GSM 5.02 section 3.3.2.3) */ SHORT b = ((rr_data->nc_data[index].control_descr.ccch_conf / 2) + 1) * n; TRACE_FUNCTION ("dat_calc_tn()"); /* * calculate the timeslot */ return ((UBYTE) ((a % b) / n) * 2); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_check_error_flag | +--------------------------------------------------------------------+ PURPOSE : In the formatter module several tests are performed to check the syntax and the semantic of the incoming messages. The results of this checks are stored in the error variables. This function sends a RR STATUS message back to the network if a mandatory or conditional error has been detected for a message received in acknowledged mode. It indicates to the calling function whether the message shall be ignored or not. */ GLOBAL BOOL dat_check_error_flag (BOOL send_rr_status) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_check_error_flag()"); /* * if an error unequal to optional info error has occured */ if (rr_data->ms_data.error.cs NEQ 0 AND rr_data->ms_data.error.cs NEQ OPTIONAL_INFO_ERROR) { if (send_rr_status) { /* * if the message has been received in acknowledged mode, * answer to the network with a RR STATUS message. */ /* Implements RR Clone findings #23 */ dat_send_rr_status_msg(rr_data->ms_data.error.cs); } } switch (rr_data->ms_data.error.cs) { /* case RRC_INVALID_MAN_INFO: this value is currently never set */ case RRC_INCORRECT_MSG: case RRC_COND_IE_ERROR: /* * Major failure in the message, ignore it */ return FALSE; default: /* * minor or no failure, process the message */ return TRUE; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_channel_mode_to_mm| +--------------------------------------------------------------------+ PURPOSE : A changed channel mode is signalled to MM. */ GLOBAL void dat_code_channel_mode_to_mm (void) { GET_INSTANCE_DATA; PALLOC (sync_ind, RR_SYNC_IND); TRACE_FUNCTION ("dat_code_channel_mode_to_mm()"); /* * set the channel type */ switch (rr_data->sc_data.chan_desc.chan_type) { case CH_TCH_F: TRACE_EVENT ("TCH/F configured"); sync_ind->chm.ch_type = CH_TCH_F; break; case CH_TCH_H_1: case CH_TCH_H_2: TRACE_EVENT ("TCH/H configured"); sync_ind->chm.ch_type = CH_TCH_H; break; default: TRACE_EVENT ("SDCCH configured"); sync_ind->chm.ch_type = CH_SDCCH; break; } /* * set the rest of the parameters */ sync_ind->ciph = NOT_PRESENT_8BIT; sync_ind->chm.ch_mode = rr_data->sc_data.ch_mode; memset(&sync_ind->mm_info, 0, sizeof(T_mm_info)); sync_ind->mm_info.valid = FALSE; memset(&sync_ind->bcch_info, 0, sizeof(T_bcch_info)); sync_ind->bcch_info.v_bcch = FALSE; sync_ind->synccs = NOT_PRESENT_16BIT; PSENDX(MM, sync_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_ciphering_to_mm | +--------------------------------------------------------------------+ PURPOSE : A changed ciphering mode is signalled to MM. */ GLOBAL void dat_code_ciphering_to_mm (UBYTE ciph_on) { PALLOC (sync_ind, RR_SYNC_IND); TRACE_FUNCTION ("dat_code_ciphering_to_mm()"); /* * set the new cipher mode */ sync_ind->ciph = ciph_on; /* * clear the rest of the parameters */ sync_ind->chm.ch_mode = NOT_PRESENT_8BIT; memset(&sync_ind->mm_info, 0, sizeof(T_mm_info)); sync_ind->mm_info.valid = FALSE; memset(&sync_ind->bcch_info, 0, sizeof(T_bcch_info)); sync_ind->bcch_info.v_bcch = FALSE; sync_ind->synccs = NOT_PRESENT_16BIT; PSENDX(MM, sync_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_reestablishment_fail | +--------------------------------------------------------------------+ PURPOSE : Indicate a failed call reestablishment to MM. If a radio link failure has occured, RR performs a cell reselection to come back to idle mode and then the reestablishment may starts. If no suitable cell is available, it may takes a long time until no service is signalled. This function is used to finish the reestablish earlier, if no candidate is available during coming back from dedicated. */ GLOBAL void dat_code_reestablishment_fail (void) { GET_INSTANCE_DATA; T_NC_DATA *rrd = &rr_data->nc_data[SC_INDEX]; PALLOC (sync_ind, RR_SYNC_IND); TRACE_FUNCTION ("dat_code_reestablishment_fail()"); sync_ind->mm_info.valid = TRUE; sync_ind->mm_info.att = rrd->control_descr.att; /* * No reestablishment */ sync_ind->mm_info.re = 1; sync_ind->mm_info.ncc = (rrd->bsic >> 3) & 7; sync_ind->mm_info.bcc = rrd->bsic & 7; sync_ind->mm_info.t3212 = rrd->control_descr.t3212; /*sync_ind->mm_info.la = !dat_forb_lai_check (SC_INDEX);*/ sync_ind->mm_info.la = (!(dat_forb_lai_check (SC_INDEX) AND dat_roam_forb_lai_check (SC_INDEX))); sync_ind->ciph = NOT_PRESENT_8BIT;; sync_ind->chm.ch_mode = NOT_PRESENT_8BIT; sync_ind->bcch_info.v_bcch = FALSE; sync_ind->synccs = NOT_PRESENT_16BIT; PSENDX (MM, sync_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_measure_report | +--------------------------------------------------------------------+ PURPOSE : RR builds a RR MEASUREMENT REPORT message for the uplink sacch, whenever it receives a measurement report from the layer 1. */ GLOBAL void dat_code_measure_report (T_MPH_MEASUREMENT_IND *report) { GET_INSTANCE_DATA; USHORT i; MCAST (meas, U_MEAS_REP); PALLOC_MSG (dl_unitdata_req, DL_UNITDATA_REQ, U_MEAS_REP);/* T_DL_UNITDATA_REQ */ TRACE_FUNCTION ("dat_code_measure_report()"); memset (&dl_unitdata_req->sdu.buf[0], 0, dl_unitdata_req->sdu.o_buf / BITS_PER_BYTE); /* * initialize C-structure for the Uplink message */ memset (meas, 0, sizeof (T_U_MEAS_REP)); /* * set message type */ meas->msg_type = U_MEAS_REP; if (report->valid) { /* * measurement report from layer 1 is valid, * then copy data to C-structure for message */ meas->meas_result.ba_used = rr_data->sc_data.ba_index; meas->meas_result.dtx_used = report->dtx; meas->meas_result.meas_valid = 0; if (rr_data->dyn_config.fho) { /* * forced handover, special test feature to simulate * a bad serving cell */ meas->meas_result.rxlev_full = 0; meas->meas_result.rxlev_sub = 0; } else { /* * take values from layer 1 */ meas->meas_result.rxlev_full = report->rx_lev_full; meas->meas_result.rxlev_sub = report->rx_lev_sub; } meas->meas_result.rxqual_full = report->rx_qual_full; meas->meas_result.rxqual_sub = report->rx_qual_sub; /* * copy neighbourcell values */ meas->meas_result.num_ncell = report->ncells.no_of_ncells; #if defined (REL99) && defined (TI_PS_FF_EMR) if ( (rr_data->sc_data.ba_list_idle EQ TRUE) OR (rr_data->sc_data.ba_list_ded EQ TRUE) ) #else /* * report ncells only if BA complete or * itīs a expansion (5ter) and the 5/5bis are sent before */ if ( (rr_data->sc_data.cd.sys_info_read & (SYS_INFO_5_READ | SYS_INFO_5BIS_READ)) EQ (SYS_INFO_5_READ | SYS_INFO_5BIS_READ) ) #endif { /* * fill ncells to the measurement report */ for (i=0;i<meas->meas_result.num_ncell;i++) { meas->meas_result.ncell[i].bsic = report->ncells.bsic[i]; /* * set position in neighbourcell list instead of channel number */ meas->meas_result.ncell[i].bcch_ncell = dat_get_ncell_pos (report->ncells.arfcn[i]); meas->meas_result.ncell[i].rx_lev_ncell = report->ncells.rx_lev[i]; TRACE_EVENT_P4 ("MR:%u[%4u] p=%u rxl=%u", i, report->ncells.arfcn[i], meas->meas_result.ncell[i].bcch_ncell, meas->meas_result.ncell[i].rx_lev_ncell); /* +++ */ } } else { /* * Table 10.5.47/GSM 04.08: Measurement Results information element * Range: 0 to 7 (See GSM 05.08) * NO-NCELL-M, Number of neighbouring cell measurements (octets 4 and 5) * * No neighbour cell measurement result := 0 * Neighbour cell information not available for serving cell := 7 */ meas->meas_result.num_ncell = 7; } } else { /* * measurement report from layer 1 is invalid */ TRACE_EVENT ("invalid Meas"); meas->meas_result.meas_valid = 1; } /* * code message and send to layer 2. */ for_dat_unitdata_req (dl_unitdata_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_ext_meas_report | +--------------------------------------------------------------------+ PURPOSE : RR builds a RR EXTENDED MEASUREMENT REPORT message for the uplink sacch. */ GLOBAL void dat_code_ext_meas_report (T_MPH_EMO_MEAS_IND *mph_emo_meas_ind) { GET_INSTANCE_DATA; USHORT *emo_arfcn = rr_data-> emo_arfcn; UBYTE c_emo_arfcn = rr_data->c_emo_arfcn; T_ext_meas_res *ext_meas_res; UBYTE *rx_lev_ncell; T_meas_results *meas_results; UBYTE i,k; MCAST (u_ext_meas_report, U_EXT_MEAS_REPORT); PALLOC_MSG (dl_unitdata_req, DL_UNITDATA_REQ, U_EXT_MEAS_REPORT); TRACE_FUNCTION ("dat_code_ext_meas_report()"); /* * initialize C-structure for the Uplink message */ memset (u_ext_meas_report, 0, sizeof (T_U_EXT_MEAS_REPORT)); ext_meas_res = &u_ext_meas_report->ext_meas_res; /* * set message type */ u_ext_meas_report->msg_type = U_EXT_MEAS_REPORT; ext_meas_res->sc_used = rr_data->emo_seq; ext_meas_res->dtx_used = mph_emo_meas_ind->dtx; rx_lev_ncell = &ext_meas_res->rx_lev_ncell[0]; meas_results = &mph_emo_meas_ind->meas_results[0]; TRACE_ASSERT( c_emo_arfcn <= MAX_EMO_CHANNELS); TRACE_ASSERT( mph_emo_meas_ind->c_meas_results <= (MAX_EMO_CHANNELS +1)); for ( k = 0; k < c_emo_arfcn; k++ ) { for ( i = 0; i < mph_emo_meas_ind->c_meas_results; i++ ) { if ( emo_arfcn[k] EQ meas_results[i].arfcn ) { rx_lev_ncell[k] = meas_results[i].rx_lev; } } } /* * code message and send to layer 2. */ for_dat_unitdata_req (dl_unitdata_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_mph_chan_mode_req | +--------------------------------------------------------------------+ PURPOSE : configure a new channel mode to layer 1. */ GLOBAL void dat_code_mph_chan_mode_req (T_D_CHAN_MOD *chan_mod) { GET_INSTANCE_DATA; PALLOC (channel_mode_req, MPH_CHANNEL_MODE_REQ); TRACE_FUNCTION ("dat_code_mph_chan_mode_req()"); memset(channel_mode_req, 0, sizeof(T_MPH_CHANNEL_MODE_REQ)); /* * configure layer 1 with multi-rate configuration if present */ if ( rr_data->sc_data.ch_mode EQ CM_AMR ) { int i; channel_mode_req->amr_conf.nscb = rr_data->sc_data.amr_conf.nscb; channel_mode_req->amr_conf.icmi = rr_data->sc_data.amr_conf.icmi; channel_mode_req->amr_conf.st_mode = rr_data->sc_data.amr_conf.st_mode; channel_mode_req->amr_conf.acs = rr_data->sc_data.amr_conf.set_amr; channel_mode_req->amr_conf.v_cod_prop = rr_data->sc_data.amr_conf.v_cod_prop; if(channel_mode_req->amr_conf.v_cod_prop) { channel_mode_req->amr_conf.c_cod_prop = rr_data->sc_data.amr_conf.c_cod_prop; for (i=0; i< channel_mode_req->amr_conf.c_cod_prop; i++) memcpy(&channel_mode_req->amr_conf.cod_prop[i], &rr_data->sc_data.amr_conf.cod_prop[i], sizeof(T_cod_prop)); } } /* * set new channel mode */ channel_mode_req->ch = chan_mod->chan_desc.chan_type; channel_mode_req->mode = chan_mod->chan_mode; PSENDX (PL, channel_mode_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_mph_ciphering_req | +--------------------------------------------------------------------+ PURPOSE : configure new cipher parameter to layer 1. */ GLOBAL void dat_code_mph_ciphering_req (UBYTE ciph_on, UBYTE algo, UBYTE * kc) { PALLOC (mph_ciphering_req, MPH_CIPHERING_REQ); TRACE_FUNCTION ("dat_code_mph_ciphering_req()"); if (ciph_on) { /* * ciphering is on, then set cipher algorithm * and Kc value. */ mph_ciphering_req->ciph.stat = CIPH_ON; mph_ciphering_req->ciph.algo = algo; memcpy (mph_ciphering_req->ciph.kc, kc, KC_STRING_SIZE); } else { /* * ciphering is off, then set default values */ mph_ciphering_req->ciph.stat = CIPH_OFF; mph_ciphering_req->ciph.algo = 0; memset (mph_ciphering_req->ciph.kc, 0, KC_STRING_SIZE); } PSENDX (PL, mph_ciphering_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_sys_info_change | +--------------------------------------------------------------------+ PURPOSE : A change in parameters of system information type 6 has been detected. The parameters are configured in layer 1. */ GLOBAL void dat_code_sys_info_change (UBYTE dtx, UBYTE pwrc, UBYTE rlt) { PALLOC (dedicated_req, MPH_DEDICATED_REQ); TRACE_FUNCTION ("dat_code_sys_info_change()"); memset (dedicated_req, 0, sizeof (T_MPH_DEDICATED_REQ)); /* * set new dtx, rlt, pwrc and ncc_permitted values */ dedicated_req->tr_para.dtx = dtx; dedicated_req->tr_para.rlt = rlt; dedicated_req->tr_para.pwrc = pwrc; dedicated_req->mod = MODE_SYS_INFO_CHANGE; PSENDX (PL, dedicated_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_mph_imm_assign_req | +--------------------------------------------------------------------+ PURPOSE : configure layer 1 after reception of an immediate assignment or immediate assignment extended message. */ GLOBAL void dat_code_mph_imm_assign_req (T_start *start, UBYTE power, UBYTE maio, T_LIST *freq_after_sti, T_LIST *freq_bef_sti) { GET_INSTANCE_DATA; PALLOC (dedicated_req, MPH_DEDICATED_REQ); TRACE_FUNCTION ("dat_code_mph_imm_assign_req()"); memset (dedicated_req, 0, sizeof (T_MPH_DEDICATED_REQ)); dedicated_req->mod = MODE_IMM_ASSIGN; /* * set starting time if available */ memcpy (&dedicated_req->start, start, sizeof (T_start)); /* * set channel type */ dedicated_req->ch_type.ch = rr_data->sc_data.chan_desc.chan_type; dedicated_req->ch_type.tn = rr_data->sc_data.chan_desc.tn; dedicated_req->ch_type.tsc = rr_data->sc_data.chan_desc.tsc; dedicated_req->ch_type.h = rr_data->sc_data.chan_desc.hop; if (rr_data->sc_data.chan_desc.hop EQ H_NO) { /* * set channel number if no hopping is configured */ dedicated_req->ch_type.arfcn = rr_data->sc_data.chan_desc.arfcn; } else { /* * set maio, hsn and hopping list, if hopping is configured */ dedicated_req->ch_type.maio = rr_data->sc_data.chan_desc.maio; dedicated_req->ch_type.hsn = rr_data->sc_data.chan_desc.hsn; /* CSI-LLD section:4.1.1.11 * This function Updates the black list with the MA list received * in immediate_assignment req */ cs_remove_BA_MA_from_black_list(rr_data->cs_data.region,freq_after_sti); srv_create_list (freq_after_sti, dedicated_req->ch_type.ma, MAX_MA_CHANNELS, TRUE, 0); } /* * set channel type 2 (only maio and mobile allocation) */ dedicated_req->ch_type2.maio = maio; /* CSI-LLD section:4.1.1.11 * This function Updates the black list with the MA list received * in immediate_assignment req */ cs_remove_BA_MA_from_black_list(rr_data->cs_data.region,freq_bef_sti); srv_create_list (freq_bef_sti, dedicated_req->ch_type2.ma, MAX_MA_CHANNELS, TRUE, 0); dedicated_req->arfcn = rr_data->nc_data[SC_INDEX].arfcn; /* * set power, dtx, rlt, pwrc, timing advance and channel mode */ dedicated_req->tr_para.power = power; dedicated_req->tr_para.dtx = rr_data->sc_data.cd.dtx; dedicated_req->tr_para.rlt = rr_data->sc_data.cd.cell_options.rlt; dedicated_req->tr_para.pwrc = rr_data->sc_data.cd.cell_options.pow_ctrl; dedicated_req->tr_para.tav = rr_data->sc_data.new_ta; dedicated_req->tr_para.mode = rr_data->sc_data.ch_mode; RR_EM_GET_HOPPING_CHANNEL(dedicated_req->ch_type.ma,dedicated_req->ch_type2.ma, dedicated_req->start.v_start,maio); PSENDX (PL, dedicated_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_mph_freq_redef_req| +--------------------------------------------------------------------+ PURPOSE : configure a new hopping list after reception of a frequency redefinition message. */ GLOBAL void dat_code_mph_freq_redef_req (T_start *start, T_LIST *hop_list) { GET_INSTANCE_DATA; T_chan_desc * chan_desc = &rr_data->sc_data.chan_desc; PALLOC (freq_redef_req, MPH_FREQ_REDEF_REQ); TRACE_FUNCTION ("dat_code_mph_freq_redef_req()"); /* * copy start time */ memcpy (&freq_redef_req->start, start, sizeof (T_start)); /* * set new hopping list */ srv_create_list (hop_list, freq_redef_req->ch_type.ma, MAX_MA_CHANNELS, TRUE,0); /* CSI-LLD section:4.1.1.11 * This function Updates the black list with the MA list received * in Frequency redifinition message */ cs_remove_BA_MA_from_black_list(rr_data->cs_data.region,hop_list); /* * set channel type, timeslot, training sequence code, * hopping indication, maio and hsn. */ freq_redef_req->ch_type.ch = chan_desc->chan_type; freq_redef_req->ch_type.tn = chan_desc->tn; freq_redef_req->ch_type.tsc = chan_desc->tsc; freq_redef_req->ch_type.h = chan_desc->hop; freq_redef_req->ch_type.maio = chan_desc->maio; freq_redef_req->ch_type.hsn = chan_desc->hsn; rr_data->mode_after_dedi = MODE_CELL_RESELECTION; EM_FREQ_REDEF; RR_EM_GET_HOPPING_CHANNEL (freq_redef_req->ch_type.ma, freq_redef_req->ch_type.ma, FALSE,0); PSENDX (PL, freq_redef_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_mph_old_chan_req | +--------------------------------------------------------------------+ PURPOSE : During channel assignment or handover the layer 2 link is suspended and a new channel is configured. Then the layer 2 connection is resumed on the new channel. If this fails, RR switches back to the old channel. The trigger for this is this function. */ GLOBAL void dat_code_mph_old_chan_req (void) { PALLOC ( mph_dedicated_fail_req, MPH_DEDICATED_FAIL_REQ); TRACE_FUNCTION ("dat_code_mph_old_chan_req()"); PSENDX (PL, mph_dedicated_fail_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_prr_channel | +--------------------------------------------------------------------+ PURPOSE : Set the channel type and the service access point identification according to the configured channel type. */ GLOBAL void dat_code_prr_channel (UBYTE *ch_type, UBYTE *sapi, UBYTE chan_type) { TRACE_FUNCTION ("dat_code_prr_channel()"); /* * SAPI is always 0 */ *sapi = SAPI_0; /* * convert air-interface coding of channel type * to internal values. */ switch (chan_type) { case CH_TCH_F: *ch_type = L2_CHANNEL_FACCH_F; break; case CH_TCH_H_1: case CH_TCH_H_2: *ch_type = L2_CHANNEL_FACCH_H; break; default: *ch_type = L2_CHANNEL_SDCCH; break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_prr_channel_sms | +--------------------------------------------------------------------+ PURPOSE : Set the channel type and the service access point identification according to the configured channel type for short messages. */ GLOBAL void dat_code_prr_channel_sms (T_DL_DATA_REQ *dl_data_req, UBYTE chan_type) { TRACE_FUNCTION ("dat_code_prr_channel_sms()"); /* * sapi is always 3 */ dl_data_req->sapi = SAPI_3; /* * channel type is SACCH if the main channel (sapi = 0) * is FACCH, else it is SDCCH. */ dl_data_req->ch_type = (chan_type < CH_SDCCH_4_0)\ ? L2_CHANNEL_SACCH : L2_CHANNEL_SDCCH; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_prr_bcch_info | +--------------------------------------------------------------------+ PURPOSE : create a list of channels from the ba_range information element of a channel release message. */ GLOBAL void dat_code_prr_bcch_info (UBYTE v_ba_range, T_ba_range * ba_range) { T_LIST list; USHORT i; USHORT j; USHORT x1; USHORT x2; TRACE_FUNCTION ("dat_code_prr_bcch_info()"); /* * initialization : the list is empty. */ srv_clear_list (&list); if (v_ba_range) { /* * only if the information element is inside the * channel release message. * Then for all ranges inside the information element. */ for (i=0;i<ba_range->c_freq_range;i++) { x1 = ba_range->freq_range[i].freq_lower; x2 = ba_range->freq_range[i].freq_higher; /* * set interval borders */ if (x1 > HIGH_CHANNEL_900) x1 = HIGH_CHANNEL_900; if (x2 > HIGH_CHANNEL_900) x2 = HIGH_CHANNEL_900; if (x1 EQ x2) { /* * add x1 to channel list if both boarders have the same value */ srv_set_channel (&list, x1); } if (x1 < x2) { /* * add x1..x2 to channel list if the boarders define a range */ for (j=x1;j<=x2;j++) srv_set_channel (&list, j); } if (x1 > x2) { /* * add LOW_CHANNEL_900..x2 and x1..HIGH_CHANNEL_900 to channel list */ for (j=LOW_CHANNEL_900;j<=HIGH_CHANNEL_900;j++) if (j <= x2 OR j>=x1) srv_set_channel (&list, j); } } /* * send the resulting list to the SIM card or store it inside the PCM */ } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_send_bcchinfo_mm | +--------------------------------------------------------------------+ PURPOSE : Send neigbour cell description to MM */ GLOBAL void dat_send_bcchinfo_mm (UBYTE *p) { PALLOC (sync_ind, RR_SYNC_IND); sync_ind->ciph = NOT_PRESENT_8BIT; sync_ind->chm.ch_mode = NOT_PRESENT_8BIT; sync_ind->mm_info.valid = FALSE; sync_ind->bcch_info.v_bcch = TRUE; sync_ind->synccs = NOT_PRESENT_16BIT; if (p) { memcpy (sync_ind->bcch_info.bcch, p, BA_BITMAP_SIZE); TRACE_EVENT_P4 ("BCCHINFO: send 16 byte to MM/SIM (%x,%x,%x,%x,...)", p[0], p[1], p[2], p[3]); } else { memset (sync_ind->bcch_info.bcch, 0, BA_BITMAP_SIZE); TRACE_EVENT ("BCCHINFO: clear SIM"); } PSENDX (MM, sync_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_convert_white_list | +--------------------------------------------------------------------+ PURPOSE : Updates White List after cell selection and cell reselection in Full service CSI-LLD section:4.1.2.2.2 */ GLOBAL void dat_convert_white_list(void) { GET_INSTANCE_DATA; U8 *p = NULL; U8 i; T_LIST tmp_list; BUF_neigh_cell_desc cd; TRACE_FUNCTION("dat_convert_white_list()"); if(rr_data->ms_data.rr_service EQ FULL_SERVICE) { TRACE_EVENT("CR white list -> CS white list"); /* Clear the old White List info */ memset(&rr_data->cs_data.white_list, 0x00, sizeof(T_CS_WHITE_LIST)); /* copy the serving cell ARFCN */ rr_data->cs_data.white_list.last_sc_arfcn = rr_data->nc_data[SC_INDEX].arfcn; /* copy the serving cell region */ rr_data->cs_data.white_list.region = rr_data->cs_data.region; /* Copy the serving cell location area identity */ memcpy(&rr_data->cs_data.white_list.last_sc_lac,&rr_data->nc_data[SC_INDEX].lai, sizeof(T_loc_area_ident)); /* Convert CR white list into T_LIST format and store the same */ for(i=0;i<=32;i+=BA_BITMAP_SIZE) { switch(i) { case 0: p = rr_data->cr_data.cr_white_list.si2; break; case 16: p = rr_data->cr_data.cr_white_list.si2bis; break; case 32: p = rr_data->cr_data.cr_white_list.si2ter; break; default: continue; } if(p NEQ NULL) { memcpy(cd.b_neigh_cell_desc,p,BA_BITMAP_SIZE); cd.o_neigh_cell_desc = 0; cd.l_neigh_cell_desc = NCELL_DESC_BIT_LEN; for_create_channel_list((T_f_range *)&cd,&tmp_list); srv_merge_list(&rr_data->cs_data.white_list.list,&tmp_list); } } /* Use last serving cell information also */ if(rr_data->cs_data.white_list.last_sc_arfcn NEQ NOT_PRESENT_16BIT) { srv_set_channel(&rr_data->cs_data.white_list.list, rr_data->cs_data.white_list.last_sc_arfcn&ARFCN_MASK); } TRACE_EVENT_P9 ( "White List:[%d]Reg,[%d]Arfcn MCC/MNC r=%x%x%x/%x%x%x/%d", rr_data->cs_data.white_list.region, rr_data->cs_data.white_list.last_sc_arfcn, rr_data->cs_data.white_list.last_sc_lac.mcc[0], rr_data->cs_data.white_list.last_sc_lac.mcc[1], rr_data->cs_data.white_list.last_sc_lac.mcc[2], rr_data->cs_data.white_list.last_sc_lac.mnc[0], rr_data->cs_data.white_list.last_sc_lac.mnc[1], rr_data->cs_data.white_list.last_sc_lac.mnc[2], rr_data->cs_data.white_list.last_sc_lac.lac); } /* Full service */ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_store_neigh_cell_desc | +--------------------------------------------------------------------+ PURPOSE : Store neigbour cell description in case of full service */ GLOBAL void dat_store_neigh_cell_desc (UBYTE si, UBYTE index, BUF_neigh_cell_desc *cd, T_LIST *new_neigh_list) { GET_INSTANCE_DATA; U8 *p = NULL; U16 o; U8 att_state = GET_STATE (STATE_ATT); #if defined(_SIMULATION_) { BOOL plmn_ok; plmn_ok = dat_plmn_equal_req (rr_data->nc_data[index].lai.mcc, rr_data->nc_data[index].lai.mnc, rr_data->ms_data.plmn.mcc, rr_data->ms_data.plmn.mnc); TRACE_EVENT_P8 ("dat_store_neigh_cell_desc(): srv:%s op:%s tried:%u, st:%s, NC%u plmn:%u CR:%d SC:%d", _rr_str_SERVICE[rr_data->ms_data.rr_service], _rr_str_FUNC[rr_data->ms_data.req_mm_service], (rr_data->cs_data.scan_mode EQ CS_SECOND_SCAN), STATE_ATT_NAME[att_state], index, plmn_ok, ((int)rr_data->nc_data[CR_INDEX].arfcn), ((int)rr_data->nc_data[SC_INDEX].arfcn)); } #endif /* 0|1 */ if (rr_data->ms_data.req_mm_service EQ FUNC_PLMN_SRCH) { /* * In states ATT_CS2 and ATT_CS3, store BA lists from SI2, 2Bis and 2Ter * inside rr_data->cr_data */ if ((att_state EQ ATT_CS2 OR att_state EQ ATT_CS3) AND (index EQ CR_INDEX)) { switch (si) { case SYS_INFO_2_MSG: p = rr_data->cr_data.cr_white_list.si2; break; case SYS_INFO_2bis_MSG: p = rr_data->cr_data.cr_white_list.si2bis; break; case SYS_INFO_2ter_MSG: p = rr_data->cr_data.cr_white_list.si2ter; break; default: return; } TRACE_EVENT_P3 ("BCCHINFO: store cd of [%d]i%u: si=%02x ", rr_data->nc_data[index].arfcn, index, si); /* compare; store and indicate only if changed */ o = cd->o_neigh_cell_desc>>3; if (p NEQ NULL) { if (memcmp (p, &cd->b_neigh_cell_desc[o], BA_BITMAP_SIZE)) { memcpy (p, &cd->b_neigh_cell_desc[o], BA_BITMAP_SIZE); } } } /* CR_INDEX */ else if((att_state EQ ATT_IDLE) AND (index EQ SC_INDEX) AND (rr_data->ms_data.rr_service EQ FULL_SERVICE)) { /* In state ATT_IDLE, store BA list directly inside the white list * (only if we are in Full Service) */ srv_copy_list (&rr_data->cs_data.white_list.list, new_neigh_list, sizeof (T_LIST)); /* Add current serving cell to White List */ srv_set_channel(&rr_data->cs_data.white_list.list, rr_data->nc_data[SC_INDEX].arfcn&ARFCN_MASK); if(si EQ SYS_INFO_2_MSG) { /* In case it is the description of system information 2 (and only then) * it should be stored in the SIM card. */ o = cd->o_neigh_cell_desc>>3; dat_send_bcchinfo_mm (&cd->b_neigh_cell_desc[o]); } } /* additional storing of current serving cell and cell-re-selection cell */ rr_data->cs_data.arfcn_sc = rr_data->nc_data[SC_INDEX].arfcn; rr_data->cs_data.arfcn_cr = rr_data->nc_data[CR_INDEX].arfcn; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_compare_request_ref | +--------------------------------------------------------------------+ PURPOSE : Reference is GSM 4.08, chapter 3.3.1.1.3.1 On receipt of a CHANNEL REQUEST message On receipt of an IMMEDIATE ASSIGNMENT or IMMEDIATE ASSIGNMENT EXTENDED message corresponding to one of its 3 last CHANNEL REQUEST messages, the message shall be identified as the channel description for the MS. */ GLOBAL BOOL dat_compare_request_ref (T_req_ref *req_ref, UBYTE * index) { GET_INSTANCE_DATA; UBYTE from; UBYTE i; TRACE_FUNCTION ("dat_compare_request_ref()"); /* * RR stores the request references for all outgoing * channel requests. The variable from indicates the * beginning of the maximum 3 last channel requests. */ from = (rr_data->ms_data.access_counter > 2) ? rr_data->ms_data.access_counter - 3 : 0; TRACE_EVENT_P4 ("compare: %d %d %d 0x%02x", req_ref->t1, req_ref->t2, req_ref->t3, req_ref->ra); TRACE_ASSERT( rr_data->ms_data.access_counter <= MAX_RACH_REQ); for (i = from; i < rr_data->ms_data.access_counter; i++) { /* * RR checks the sending time T1/T2/T3 of the channel * request message and the content of the message. * If all matches the immediate assignment (extended) * message is identified for the MS. */ TRACE_EVENT_P5 ("with[%u]: %d %d %d 0x%02x", i, rr_data->used_frame_no[i].t1, rr_data->used_frame_no[i].t2, rr_data->used_frame_no[i].t3, rr_data->used_channel_ref[i]); if (rr_data->used_frame_no[i].t1 EQ req_ref->t1 AND rr_data->used_frame_no[i].t2 EQ req_ref->t2 AND rr_data->used_frame_no[i].t3 EQ req_ref->t3 AND rr_data->used_channel_ref[i] EQ req_ref->ra) { *index = i; return TRUE; } } /* * The message is not for the MS */ return FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_disconnect_link | +--------------------------------------------------------------------+ PURPOSE : After reception of a channel release message this function starts the disconnection of the link in layer 2. */ GLOBAL void dat_disconnect_link (USHORT cause) { GET_INSTANCE_DATA; UBYTE ch_type; PALLOC (dl_release_req, DL_RELEASE_REQ); TRACE_FUNCTION ("dat_disconnect_link()"); rr_data->rel_cause = cause; /* * set channel type and sapi according the configured channel * configuration */ dat_code_prr_channel (&dl_release_req->ch_type, &dl_release_req->sapi, rr_data->sc_data.chan_desc.chan_type); ch_type = dl_release_req->ch_type; dl_release_req->mode = DL_NORMAL_RELEASE; PSENDX (DL, dl_release_req); /* * control layer 2 release. The timer shall be set in a way * that layer 2 has enough time for at least two DISC frames. * So the value of the timer depends on the channel type * (SDCCH or FACCH). */ if (ch_type EQ L2_CHANNEL_SDCCH) { TIMERSTART (T3110, T3110_SDCCH_VALUE); } else { TIMERSTART (T3110, T3110_VALUE); } SET_STATE (STATE_DAT, DAT_CHAN_REL); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_fill_mobile_identity | +--------------------------------------------------------------------+ PURPOSE : In several update message the mobile identity must be set. For mobile terminated message the mobile identity of the paging message must be used. For mobile originated connections the mobile identity type depends on the availability of the mobile identities in this order: TMSI, IMSI, no identity */ static void dat_fill_mobile_identity (USHORT fill_type, T_mob_ident *moid) { GET_INSTANCE_DATA; UBYTE mobile_type; TRACE_FUNCTION ("dat_fill_mobile_identity()"); memset (moid, 0, sizeof (T_mob_ident)); /* * for MTC set the type according the paging identity type. */ if (fill_type EQ ESTCS_PAGING) mobile_type = rr_data->page_identity_type; else { /* * for MOC set the type according the availability */ if (rr_data->ms_data.tmsi_available) mobile_type = TYPE_TMSI; else mobile_type = (rr_data->ms_data.imsi_available) ? TYPE_IMSI : TYPE_NO_ID; } /* * fill the identity according the calculated type */ switch (mobile_type) { case TYPE_TMSI: TRACE_EVENT ("FILL TMSI"); moid->ident_type = TYPE_TMSI; moid->tmsi_1.l_tmsi_1 = 32; moid->tmsi_1.o_tmsi_1 = 0; moid->odd_even = 0; moid->v_tmsi_1 = TRUE; ccd_codeByte (moid->tmsi_1.b_tmsi_1, 0, 8, (UBYTE)(rr_data->ms_data.tmsi_binary >> 24)); ccd_codeByte (moid->tmsi_1.b_tmsi_1, 8, 8, (UBYTE)(rr_data->ms_data.tmsi_binary >> 16)); ccd_codeByte (moid->tmsi_1.b_tmsi_1, 16, 8, (UBYTE)(rr_data->ms_data.tmsi_binary >> 8)); ccd_codeByte (moid->tmsi_1.b_tmsi_1, 24, 8, (UBYTE)rr_data->ms_data.tmsi_binary); break; case TYPE_IMSI: TRACE_EVENT ("FILL IMSI"); memcpy (moid, &rr_data->ms_data.imsi, sizeof (T_mob_ident)); break; default: TRACE_EVENT ("FILL NOTHING"); memset (moid, 0, sizeof (T_mob_ident)); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_check_forb_list | +--------------------------------------------------------------------+ PURPOSE : In automatic mode a cell shall be only selected if it is not member of a forbidden location area list. This function checks the membership in a forbidden LAI independant of the selected mode (manual or automatic). */ LOCAL BOOL dat_check_forb_list (int list_type, UBYTE index) { GET_INSTANCE_DATA; int i; T_loc_area_ident *forb_list; TRACE_FUNCTION ("dat_check_forb_list()"); if (list_type EQ FORBIDDEN_LIST_NORMAL) forb_list = &rr_data->ms_data.forb_lac_list[0]; else forb_list = &rr_data->ms_data.roam_forb_lac_list[0]; TRACE_ASSERT(index < NCELL_SIZE); /* * * check only in automatic mode * * if ((rr_data->ms_data.operation_mode & 0x40) EQ 0) M_MAN */ { /* * check all entries of this list */ for (i = 0; i < MAX_LAI; i++) { if ((rr_data->nc_data[index].lai.lac EQ forb_list[i].lac) AND dat_plmn_equal_req (rr_data->nc_data[index].lai.mcc, rr_data->nc_data[index].lai.mnc, forb_list[i].mcc, forb_list[i].mnc))/*lint !e661 !e662 (possible access/creation of out-of-bounds pointer)*/ { /* * the check is failed if the location area code is stored. */ return FALSE; } } } /* * the check has passed. */ return TRUE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_forb_lai_check | +--------------------------------------------------------------------+ PURPOSE : In automatic mode a cell shall be only selected if it is not member of a forbidden location area list. */ GLOBAL BOOL dat_forb_lai_check (UBYTE index) { TRACE_FUNCTION ("dat_forb_lai_check()"); return dat_check_forb_list (FORBIDDEN_LIST_NORMAL, index); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_roam_forb_lai_check | +--------------------------------------------------------------------+ PURPOSE : In automatic mode a cell shall be only selected if it is not member of a forbidden location area list. */ GLOBAL BOOL dat_roam_forb_lai_check (UBYTE index) { TRACE_FUNCTION ("dat_roam_forb_lai_check()"); return dat_check_forb_list (FORBIDDEN_LIST_ROAMING, index); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_get_background_and_bits| +--------------------------------------------------------------------+ PURPOSE : The content of a channel request consists of two parts: The establishment cause and a random value. The function calculates the establishment cause (here defined as background) and the number of bits for the random value. The establishment cause inside the channel request message depends on several parameters: the internal used establishment cause, the last used channel the NECI-Flag in the system information message the needed channel indicated in a paging message the mobile station capabilities and whether a TCH fullrate is needed The abbreviation IG means Ignore. In this case the parameter is not relevant for the calculation. */ #ifdef GPRS #define TABLE_SIZE 30 #else #define TABLE_SIZE 21 #endif static const CODE_TABLE coding_table [TABLE_SIZE] = /* * establish cause last NECI channel MS TCH/F Back- Bits * channel needed cap. needed ground */ { ESTCS_EMERGENCY_CALL, IG, IG, IG, IG, IG, 0xA0, 5, ESTCS_REESTABLISHMENT, TCHFCH, IG, IG, IG, IG, 0xC0, 5, ESTCS_REESTABLISHMENT, TCHHCH, 0, IG, IG, IG, 0xC0, 5, ESTCS_REESTABLISHMENT, TCHHCH, 1, IG, IG, IG, 0x68, 2, #ifdef GPRS ESTCS_GPRS_PAGING, IG, IG, ANYCH, IG, IG, 0x80, 5, ESTCS_GPRS_PAGING, IG, IG, TCHFCH, FULL, IG, 0x80, 5, ESTCS_GPRS_PAGING, IG, IG, TCHHFCH, FULL, IG, 0x80, 5, ESTCS_GPRS_PAGING, IG, IG, TCHFCH, DUAL, IG, 0x20, 4, ESTCS_GPRS_PAGING, IG, IG, TCHHFCH, DUAL, IG, 0x30, 4, ESTCS_GPRS_PAGING, IG, IG, SDCCHCH, IG, IG, 0x10, 4, ESTCS_GPRS_PAGING, IG, IG, IG, SIGN, IG, 0x10, 4, #endif ESTCS_PAGING, IG, IG, ANYCH, IG, IG, 0x80, 5, ESTCS_PAGING, IG, IG, TCHFCH, FULL, IG, 0x80, 5, ESTCS_PAGING, IG, IG, TCHHFCH, FULL, IG, 0x80, 5, ESTCS_PAGING, IG, IG, TCHFCH, DUAL, IG, 0x20, 4, ESTCS_PAGING, IG, IG, TCHHFCH, DUAL, IG, 0x30, 4, ESTCS_PAGING, IG, IG, SDCCHCH, IG, IG, 0x10, 4, ESTCS_PAGING, IG, IG, IG, SIGN, IG, 0x10, 4, ESTCS_MOC_SPEECH, IG, 0, IG, IG, IG, 0xE0, 5, ESTCS_MOC_SPEECH, IG, 1, IG, DUAL, FALSE, 0x40, 4, ESTCS_MOC_SPEECH, IG, IG, IG, IG, IG, 0xE0, 5, ESTCS_MOC_DATA, IG, 0, IG, IG, IG, 0xE0, 5, ESTCS_MOC_DATA_HR_SUFF, IG, 1, IG, DUAL, FALSE, 0x50, 4, ESTCS_MOC_DATA, IG, IG, IG, IG, IG, 0xE0, 5, ESTCS_LOCATION_UPDATING, IG, 0, IG, IG, IG, 0x00, 5, /* new */ ESTCS_LOCATION_UPDATING, IG, 1, IG, IG, IG, 0x00, 4, ESTCS_MOC_SS_SMS, IG, 0, IG, IG, IG, 0xE0, 5, #ifndef GPRS ESTCS_MOC_SS_SMS, IG, 1, IG, IG, IG, 0x10, 4 #else ESTCS_MOC_SS_SMS, IG, 1, IG, IG, IG, 0x10, 4, ESTCS_GPRS_1P, IG, IG, IG, IG, IG, 0x78, 3, ESTCS_GPRS_SB, IG, IG, IG, IG, IG, 0x70, 3 #endif }; static void dat_get_background_and_bits (UBYTE *background, UBYTE *bits) { GET_INSTANCE_DATA; UBYTE i; USHORT ms_capability; TRACE_FUNCTION ("dat_get_background_and_bits()"); /* * initialise the output parameter */ *background = 0; *bits = 5; ms_capability = SIGN; /* * check the support of vocoder */ if (FldGet(rr_data->mscap.chnMode, VocSup)) { ms_capability = (FldGet (rr_data->mscap.chnMode, hrSup)) ? DUAL : FULL; } /* * go through the table until all criterions are passed (or can be ignored). */ for (i = 0; i < TABLE_SIZE; i++) { /* * check internal establishment cause */ if (rr_data->ms_data.establish_cause NEQ coding_table[i].cause) continue; /* * check last used channel if applicable */ if (coding_table[i].last_channel NEQ IG) { if (rr_data->ms_data.last_used_channel NEQ coding_table[i].last_channel) continue; } /* * check new establishment cause indication flag if applicable */ if (coding_table[i].neci_flag NEQ IG) { if (rr_data->nc_data[SC_INDEX].select_para.neci NEQ coding_table[i].neci_flag) continue; } /* * check the channel needed indication of the paging messages * if applicable */ if (coding_table[i].channel_needed NEQ IG) { if (rr_data->ms_data.channel_needed NEQ coding_table[i].channel_needed) continue; } /* * check the MS capability if applicable */ if (coding_table[i].ms_capability NEQ IG) { if (ms_capability NEQ coding_table[i].ms_capability) continue; } /* * check the TCH Fullrate needed flag is applicable. */ if (coding_table[i].tch_f_needed NEQ IG) { if ((rr_data->ms_data.establish_cause NEQ ESTCS_MOC_SPEECH) AND (rr_data->ms_data.establish_cause NEQ ESTCS_MOC_DATA_HR_SUFF)) continue; } /* * add this point all criterions are passed, so use the table contents. */ *background = coding_table[i].background; *bits = coding_table[i].bits; return; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_get_burst | +--------------------------------------------------------------------+ PURPOSE : This functions adds a random value to the channel request content. The random value is calculated from a well distributed table. */ static const UBYTE random_values[32] = { 9, 27, 17, 6, 10, 15, 2, 23, 29, 14, 4, 26, 18, 0, 31, 13, 21, 1, 30, 22, 5, 24, 20, 8, 7, 28, 16, 11, 25, 12, 3, 19 }; static const UBYTE mask[] = { 3, 7, 15, 31 }; static UBYTE dat_get_burst (UBYTE background, UBYTE bits) { GET_INSTANCE_DATA; UBYTE random_value; TRACE_FUNCTION ("dat_get_burst()"); rr_data->ms_data.index++; rr_data->ms_data.index %= 32; random_value = random_values[rr_data->ms_data.index]; #ifdef GPRS if( (rr_data->ms_data.establish_cause EQ ESTCS_GPRS_1P) AND ((random_value & mask[bits - 2]) EQ 7) ) { return (background + 6); } #endif return (background + (random_value & mask[bits - 2])); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_get_delta | +--------------------------------------------------------------------+ PURPOSE : Reference GSM 4.08, chapter 3.3.1.1.2 Initiation of the immediate assignment procedure The RR entity of the mobile station initiates the immediate assignment procedure by scheduling the sending on the RACH and leaving idle mode. It then sends maximally M + 1 CHANNEL REQUEST messages on the RACH in a way such that: - the number of slots belonging to the mobile station's RACH between initiation of the immediate assignment procedure and the first CHANNEL REQUEST message (excluding the slot containing the message itself) is a random value drawn randomly for each new initial assignment initiation with uniform probability distribution in the set {0, 1, ..., max (T,8) - 1}; - the number of slots belonging to the mobile station's RACH between two successive CHANNEL REQUEST messages (excluding the slots containing the messages themselves) is a random value drawn randomly for each new transmission with uniform probability distribution in the set {S, S + 1, ..., S + T - 1}; Here, T is the value of the parameter "Tx-integer" broadcast on the BCCH; M is the value of the parameter "max retrans" broadcast on the BCCH; S is a parameter depending on the CCCH configuration and on the value of Tx-integer as defined in table 3.1/GSM 04.08. Table 3.1/GSM 04.08: Values of parameter S +-----------------------------------------------------+ + TX-integer + non combined CCCH + combined CCH/SDCCH + +------------+-------------------+--------------------+ + 3,8,14,50 + 55 + 41 + + 4,9,16 + 76 + 52 + + 5,10,20 + 109 + 58 + + 6,11,25 + 163 + 86 + + 7,12,32 + 217 + 115 + +-----------------------------------------------------+ */ static const CONVERT_TXINTEGER convert_table[MAX_TX_INTEGER] = /* * T S non combined S combined Tx-integer */ { 3, 55, 41, /* 0 */ 4, 76, 52, /* 1 */ 5, 109, 58, /* 2 */ 6, 163, 86, /* 3 */ 7, 217, 115, /* 4 */ 8, 55, 41, /* 5 */ 9, 76, 52, /* 6 */ 10, 109, 58, /* 7 */ 11, 163, 86, /* 8 */ 12, 217, 115, /* 9 */ 14, 55, 41, /* 10 */ 16, 76, 52, /* 11 */ 20, 109, 58, /* 12 */ 25, 163, 86, /* 13 */ 32, 217, 115, /* 14 */ 50, 55, 41 /* 15 */ }; static UBYTE dat_get_delta (UBYTE i) { GET_INSTANCE_DATA; USHORT index = rr_data->nc_data[SC_INDEX].rach.tx_integer; USHORT n; USHORT result=0; TRACE_FUNCTION ("dat_get_delta()"); /* * calculate righ boarder of the interval. */ TRACE_ASSERT( index < MAX_TX_INTEGER ); if( index < MAX_TX_INTEGER) { n = (i EQ 0) ? att_max (convert_table[index].t, 8) - 1 : convert_table[index].t - 1; /* * calculate random value */ result = dat_random ((USHORT)(n+1)); /* * If it is not the first value, add left boarder S */ if (i NEQ 0) { /* * in according to GSM 4.08, section 10.5.2.11 (Control Channel Description) * and section 3.3.1.1.2 (Initiation of the immediate assignment procedure) */ result += (rr_data->nc_data[SC_INDEX].control_descr.ccch_conf EQ COMB_CCCH_COMB) ? convert_table[index].s_combined : convert_table[index].s_non_combined; } } return (UBYTE)result; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_get_ncell_pos | +--------------------------------------------------------------------+ PURPOSE : for uplink SACCH RR MEASUREMENT REPORT message the position of a cell inside the neighbourcell list must be calculated. This is done by this function. */ static UBYTE dat_get_ncell_pos (USHORT channel) { GET_INSTANCE_DATA; UBYTE i; TRACE_FUNCTION ("dat_get_ncell_pos()"); /* * the loop counter i is the position inside the actual * neighbourcell list. */ for (i=0; i<MAX_NEIGHBOURCELLS;i++) { if (channel EQ rr_data->act_ncell_list[i]) { /* * channel is found, then return the position. */ return i; } } return 0; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_eplmn_equal_req | +--------------------------------------------------------------------+ PURPOSE : Compare found PLMN with all PLMNs in EPLMN list */ static BOOL dat_eplmn_equal_req(const UBYTE *mcc, const UBYTE *mnc) { GET_INSTANCE_DATA; UBYTE i; TRACE_FUNCTION("dat_eplmn_equal_req"); if(rr_data->ms_data.v_eq_plmn) { for(i = 0; i < RR_EPLMNLIST_SIZE; i++) { if(!memcmp(rr_data->ms_data.eq_plmn_list[i].mcc, mcc, SIZE_MCC) && !memcmp(rr_data->ms_data.eq_plmn_list[i].mnc, mnc, SIZE_MNC)) return TRUE; } } return FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_plmn_equal_req | +--------------------------------------------------------------------+ PURPOSE : The function checks whether the given mobile country code and the given mobile network code describes the requested PLMN, eg. the HPLMN distilled from the IMSI. This is not exactly the algorithm as shown for HPLMN matching as shown in 03.22 Normative Annex A, this version here is more universal. */ GLOBAL BOOL dat_plmn_equal_req (const UBYTE *bcch_mcc, const UBYTE *bcch_mnc, const UBYTE *mm_mcc, const UBYTE *mm_mnc) { GET_INSTANCE_DATA; if(((rr_data->ms_data.operation_mode >> SHIFT_FOR_SEARCH_OFFSET) & 1) EQ M_AUTO && rr_data->ms_data.req_mm_service NEQ FUNC_LIM_SERV_ST_SRCH) { /* Check for equivalent EPLMNs */ if(dat_eplmn_equal_req(bcch_mcc, bcch_mnc)) return TRUE; } /* Check MCC */ if (memcmp (mm_mcc, bcch_mcc, SIZE_MCC) NEQ 0) return FALSE; /* Check first 2 MNC digits */ if (memcmp (mm_mnc, bcch_mnc, 2) NEQ 0) return FALSE; /* Check for full match */ if (mm_mnc[2] EQ bcch_mnc[2]) return TRUE; /* The 3rd digit of the MNC differs */ if ((bcch_mcc[0] EQ 3) AND (bcch_mcc[1] EQ 1) AND INRANGE(0,bcch_mcc[2],6)) { /* * The MCC is in the range 310..316, this means North America. * The zero suffix rule applies. */ return (((mm_mnc[2] EQ 0xf) AND (bcch_mnc[2] EQ 0x0)) OR ((mm_mnc[2] EQ 0x0) AND (bcch_mnc[2] EQ 0xf))); } return (bcch_mnc[2] EQ 0xf); } GLOBAL BOOL dat_hplmn (const UBYTE *mcc, const UBYTE *mnc) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_hplmn()"); /* * only if a SIM is inserted and an IMSI is available */ if (!rr_data->ms_data.imsi_available) return FALSE; if ((rr_data->ms_data.ahplmn.v_plmn EQ V_PLMN_PRES) AND (rr_data->ms_data.req_mm_service EQ FUNC_PLMN_SRCH)) { /* * If AHPLMN is available * do not compare the mcc, mnc from IMSI for the HPLMN * use the AHPLMN */ return dat_plmn_equal_req (mcc, mnc, rr_data->ms_data.ahplmn.mcc, rr_data->ms_data.ahplmn.mnc); } return dat_plmn_equal_req (mcc, mnc, &rr_data->ms_data.imsi.ident_dig[0], &rr_data->ms_data.imsi.ident_dig[3]); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_hplmn_country | +--------------------------------------------------------------------+ PURPOSE : The function checks whether the given mobile country code is equal to the first three digits of the IMSI. The first three digits of the IMSI are equal to the mobile country code of the HPLMN. */ static BOOL dat_hplmn_country (const UBYTE *mcc) { GET_INSTANCE_DATA; SHORT i; UBYTE mcc_digit; TRACE_FUNCTION ("dat_hplmn_country()"); /* * Only if an IMSI is available */ if (rr_data->ms_data.imsi_available) { /* EM_HPLMN_SEARCH_STARTED; - Not supported*/ for (i = 0; i < SIZE_MCC; i++) { if((rr_data->ms_data.ahplmn.v_plmn EQ V_PLMN_PRES) AND (rr_data->ms_data.req_mm_service EQ FUNC_PLMN_SRCH)) { /* * If AHPLMN is available * do not compare the mcc from IMSI for the HPLMN * use the MM req HPLMN */ mcc_digit = rr_data->ms_data.ahplmn.mcc[i]; } else { mcc_digit = rr_data->ms_data.imsi.ident_dig[i]; } /* * if one of the three first digits of the IMSI is unequal to * the mobile country code, it is not the HPLMN country. */ if (mcc[i] NEQ mcc_digit) { return FALSE; } } EM_HPLMN_SEARCH_PASSED; return TRUE; } return FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_imsi_mod_1000 | +--------------------------------------------------------------------+ PURPOSE : Calculate IMSI modulo 1000. That means take the last three digits of the IMSI. The length of the IMSI (and so the number of digits overall) is variable. This value is needed for calculation of the paging group. */ static SHORT dat_imsi_mod_1000 (void) { GET_INSTANCE_DATA; SHORT i = 0; SHORT ret = 0; int n; TRACE_FUNCTION ("dat_imsi_mod_1000()"); while (rr_data->ms_data.imsi.ident_dig[i] < 0x0A) i++; if (i) { for (n = MAXIMUM (i-3, 0); n <= MAXIMUM (i-1, 0); n++) { ret = ret * 10 + rr_data->ms_data.imsi.ident_dig[n]; } } return ret; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_no_of_paging_blocks | +--------------------------------------------------------------------+ PURPOSE : The function calculates the number of paging blocks. For 51-Multiframe the following condition exists: A non-combined CCCH configuration has 9 CCCH Blocks. A combined CCCH configuration has 3 CCCH Blocks. From this n CCCH Blocks BS_AG_BLKS_RES blocks are reserved for AGCH (access grant channels for immediate assignment). The rest is reserved for PCH (Paging Channel). This number must be multiplied by the BS_PA_MFRMS parameter (internally stored is the air-interface coding, add 2 for the real value). The BS_PA_MFRMS parameter defines the number of 51-Multiframes until the paging blocks are repeated. */ static SHORT dat_no_of_paging_blocks (UBYTE index) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_no_of_paging_blocks()"); /* in according to GSM 4.08 section 10.5.2.11, table 10.5.33 */ if (rr_data->nc_data[index].control_descr.ccch_conf EQ COMB_CCCH_COMB) { /* * combined CCCH, * * number of paging blocks = (3 - BS_AG_BLKS_RES) * BS_PA_MFRMS * * Maximum function only for security reasons, BCCH coding range is 0..7, * but allowed is only 0..2. */ return ((att_max (1, (UBYTE)(3 - rr_data->nc_data[index].control_descr. bs_ag_blks_res))) * ((UBYTE)(2 + rr_data->nc_data[index].control_descr.bs_pa_mfrms))); } else { /* * non-combined CCCH, * * number of paging blocks = (9 - BS_AG_BLKS_RES) * BS_PA_MFRMS */ return ((9 - rr_data->nc_data[index].control_descr.bs_ag_blks_res) * (2 + rr_data->nc_data[index].control_descr.bs_pa_mfrms)); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_owner_of_auth_0_to_9 | +--------------------------------------------------------------------+ PURPOSE : It is checked whether the MS is owner of at least one of the normal classes 0 to 9. The coding on the SIM card is in opposite to the coding on the BCCH. */ static BOOL dat_owner_of_auth_0_to_9 (void) { GET_INSTANCE_DATA; BOOL result = FALSE; /* * get bits 0 to 9 from SIM card and BCCH */ USHORT ms_classes = rr_data->ms_data.access_classes & 0x3FF; USHORT plmn_classes = rr_data->nc_data[SC_INDEX].rach.ac & 0x3FF; TRACE_FUNCTION ("dat_owner_of_auth_0_to_9()"); /* * check only if IMSI is available * else no valid classes of the SIM card available */ if (rr_data->ms_data.imsi_available) { /* * check classes */ if ((ms_classes & (~plmn_classes)) NEQ 0) result = TRUE; } return result; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_owner_of_auth_11_to_15 | +--------------------------------------------------------------------+ PURPOSE : It is checked whether the MS is owner of at least one of the normal classes 11 to 15. The coding on the SIM card is in opposite to the coding on the BCCH. */ static BOOL dat_owner_of_auth_11_to_15 (void) { GET_INSTANCE_DATA; BOOL result = FALSE; /* * get bits 11 to 15 from the SIM card and the BCCH. */ USHORT ms_classes = rr_data->ms_data.access_classes & 0xF800; USHORT plmn_classes = rr_data->nc_data[SC_INDEX].rach.ac & 0xF800; TRACE_FUNCTION ("dat_owner_of_auth_11_to_15()"); /* * check only if IMSI is available * else no valid classes of the SIM card available */ if (rr_data->ms_data.imsi_available) { if (! dat_hplmn (rr_data->nc_data[SC_INDEX].lai.mcc, rr_data->nc_data[SC_INDEX].lai.mnc)) { /* * ignore bit 11 and 15 if not in the HPLMN */ ms_classes = ms_classes & 0x7000; plmn_classes = plmn_classes & 0x7000; } if (! dat_hplmn_country (rr_data->nc_data[SC_INDEX].lai.mcc)) { /* * ignore bit 12 to 14 if not in the HPLMN country */ ms_classes = ms_classes & 0x8F00; plmn_classes = plmn_classes & 0x8F00; } /* * check classes */ if ((ms_classes & (~plmn_classes)) NEQ 0) result = TRUE; } return result; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_random | +--------------------------------------------------------------------+ PURPOSE : The function calculates a random value in the range 0..n-1. The algorithm uses the system time as a base for the random value calculation. */ GLOBAL USHORT dat_random (USHORT n) { GET_INSTANCE_DATA; T_TIME time_val; static USHORT random_value = 0; TRACE_FUNCTION ("dat_random()"); /* * for module testing the random component can be switched off */ if (rr_data->dyn_config.no_sys_time) time_val = 0; else vsi_t_time (VSI_CALLER &time_val); /* * increment the base of the calculation by the system time. */ random_value += (USHORT) time_val; /* * calculate the value in the range 0...n.1 */ return (random_value % n); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_release_connection | +--------------------------------------------------------------------+ PURPOSE : The function is called after receiving MPH_STOP_DEDICATED_CNF from L1 following disconnection of L2 connection. */ GLOBAL void dat_release_connection (void) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_release_connection()"); switch (GET_STATE (STATE_DAT)) { case DAT_IMM_ASS: /* * Layer 2 disconnection is initiated by MM through RR_ABORT_REQ */ if(rr_data->rel_cause EQ RRCS_MM_ABORTED) { dat_rr_release_ind(RRCS_MM_ABORTED, SAPI_0); } break; case DAT_IMM_ASS_1: /* * Layer 2 disconnection is initiated by MM through RR_ABORT_REQ */ if(rr_data->rel_cause EQ RRCS_MM_ABORTED) { dat_rr_release_ind(RRCS_MM_ABORTED, SAPI_0); break; } /* *DL establishment failure during immediate assignment */ switch (rr_data->ms_data.establish_cause) { #ifdef GPRS case ESTCS_GPRS_PAGING: dat_stop_dcch_ind ((UBYTE)rr_data->dcch_stop_cause); break; case ESTCS_PAGING: if(!rr_data->repeat_est) dat_rr_release_ind(rr_data->rel_cause, SAPI_0); #else case ESTCS_PAGING: #endif break; default: dat_rr_release_ind(rr_data->rel_cause, SAPI_0); break; } break; default: dat_rr_release_ind (rr_data->rel_cause, SAPI_0); break; } /* * clear state of data transfer process and start * cell reselection to come back to idle mode. * Inform GRR, and wait for CR_RSP */ att_leave_dedicated(); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_send_random_bursts | +--------------------------------------------------------------------+ PURPOSE : The function configures layer 1 to send 2 to 8 random bursts during connection establishment */ /* * conversion of the air-interface coding (0..3) for the * number of random bursts to be send */ static const UBYTE max_attempt[MAX_RACH_RETRANS_VAL] = { 2, 3, 5, MAX_RACH_REQ}; static void dat_send_random_bursts (void) { GET_INSTANCE_DATA; UBYTE i; UBYTE background; UBYTE bits; PALLOC (mph_random_access_req, MPH_RANDOM_ACCESS_REQ); TRACE_FUNCTION ("dat_send_random_bursts()"); /* * calculate the background and the number of bits for the * random part depending on the establishment cause. */ dat_get_background_and_bits (&background, &bits); TRACE_EVENT("reset rej_rec"); rr_data->imm_ass_rej_rec = FALSE; /* * initialize the primitive and parameter for calculation */ rr_data->ms_data.access_counter = 0; TRACE_ASSERT( rr_data->nc_data[SC_INDEX].rach.max_retrans < MAX_RACH_RETRANS_VAL ); rr_data->ms_data.max_attempt = max_attempt[rr_data->nc_data [SC_INDEX].rach.max_retrans]; memset (&mph_random_access_req->send_mode, 0, sizeof (T_send_mode)); mph_random_access_req->send_mode.no = rr_data->ms_data.max_attempt; /* * for all random bursts */ TRACE_ASSERT( rr_data->ms_data.max_attempt <= MAX_RACH_REQ ); for (i = 0; i < rr_data->ms_data.max_attempt; i++) { /* * calculate time until the random burst must be send */ mph_random_access_req->send_mode.delta[i] = dat_get_delta (i); /* * calculate the random burst content and store it for * later comparision with the incoming immediate assignment * messages. */ mph_random_access_req->send_mode.rach[i] = rr_data->used_channel_ref[i] = dat_get_burst (background, bits); /* TRACE_EVENT_P3 ("RA %u: ref=0x%02x delta=%u", i, rr_data->used_channel_ref[i], mph_random_access_req->send_mode.delta[i]); */ } /* * configure layer 1. */ PSENDX (PL, mph_random_access_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_set_last_used_channel | +--------------------------------------------------------------------+ PURPOSE : The last used channel during connection must be stored for the case of call re-establishment. */ GLOBAL void dat_set_last_used_channel (T_chan_desc *chan_desc) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_set_last_used_channel()"); /* * depending on the air-interface coding for the channel type */ switch (chan_desc->chan_type) { case CH_TCH_F: /* * Traffic channel full rate */ rr_data->ms_data.last_used_channel = TCHFCH; break; case CH_TCH_H_1: case CH_TCH_H_2: /* * Traffic channel half rate */ rr_data->ms_data.last_used_channel = TCHHCH; break; default: /* * SDCCH */ rr_data->ms_data.last_used_channel = SDCCHCH; break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_start_immediate_assign | +--------------------------------------------------------------------+ PURPOSE : start of the immediate assignment procedure after getting a RR_ESTABLISH_REQ from MM for a mobile originated connection or a MPH_PAGING_IND from layer 1 for a mobile terminated connection. */ GLOBAL void dat_start_immediate_assign (USHORT cause) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_start_immediate_assign()"); /* * synchronize attachment process to connection establishment state */ att_dat_con_est (); /* * initialize parameters for random access procedure */ rr_data->ms_data.index = dat_random (32); rr_data->ms_data.establish_cause = cause; rr_data->ms_data.access_counter = 0; rr_data->ms_data.all_conf_received = FALSE; /* * if connection is too short to get one measurement report from layer 1, * initialize the structure with the previous idle value */ rr_data->ms_data.measurement_report.rx_lev_full = rr_data->nc_data[SC_INDEX].rxlev; TRACE_EVENT_P1 ("imm ass SC=[%u]",rr_data->nc_data[SC_INDEX].arfcn); /* * send random bursts and wait for immediate assignment */ dat_send_random_bursts (); SET_STATE (STATE_DAT, DAT_IMM_ASS); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_start_sabm | +--------------------------------------------------------------------+ PURPOSE : After successful immediate assignment procedure the layer 1 is configured on a dedicated control channel (SDCCH or FACCH). Now the layer 2 connection must be established. This is done by this function. Layer 2 sends a Paging response in case of mobile terminated connection piggy-backed on the SABM. In case of mobile terminated connection the piggy-backed layer 3 message is coming from MM. */ GLOBAL void dat_start_sabm (void) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_start_sabm()"); if (rr_data->ms_data.establish_cause EQ ESTCS_PAGING #ifdef GPRS OR rr_data->ms_data.establish_cause EQ ESTCS_GPRS_PAGING #endif ) { MCAST (pag_res, U_PAG_RES); PALLOC_MSG (establish_req, DL_ESTABLISH_REQ, U_PAG_RES); dat_code_prr_channel (&establish_req->ch_type, &establish_req->sapi, rr_data->sc_data.chan_desc.chan_type); /* * if it is a mobile terminated connection, * fill the C-Structure for a PAGING RESPONSE message. */ pag_res->msg_type = U_PAG_RES; pag_res->ciph_key_num.key_seq = rr_data->ms_data.cksn; pag_res->mob_class_2 = rr_data->ms_data.classmark2; pag_res->mob_class_2.rf_pow_cap = att_get_power (); /* * fill mobile identity and send it to layer 2 */ dat_fill_mobile_identity (ESTCS_PAGING, &pag_res->mob_ident); for_dat_est_req_content (establish_req); } else { /* * mobile originated connection. set sdu with message from MM * and send it to layer 2. */ PALLOC_SDU (establish_req, DL_ESTABLISH_REQ, ((MAX_L2_FRAME_SIZE * BITS_PER_BYTE) - ENCODE_OFFSET)); dat_code_prr_channel (&establish_req->ch_type, &establish_req->sapi, rr_data->sc_data.chan_desc.chan_type); /*lint -e419 (Warning -- Apparent data overrun for function memcpy exceeds argument 1)*/ establish_req->sdu.o_buf = rr_data->ms_data.l3msg.offset; establish_req->sdu.l_buf = rr_data->ms_data.l3msg.length; memcpy (establish_req->sdu.buf, rr_data->ms_data.l3msg.buffer, MAX_L2_FRAME_SIZE); /*lint +e419 (Warning -- Apparent data overrun for function memcpy exceeds argument 1)*/ for_dat_est_req_not_coding (establish_req); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_test_sim_available | +--------------------------------------------------------------------+ PURPOSE : The function checks whether a test SIM is available or not. */ GLOBAL BOOL dat_test_sim_available (void) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_test_sim_available()"); #if defined (_SIMULATION_) /* * some traces for debugging. */ if (rr_data->ms_data.operation_mode & 0x80) { TRACE_FUNCTION ("Test SIM available"); } else { TRACE_FUNCTION ("No Test SIM available"); } #endif return ((rr_data->ms_data.operation_mode >> SHIFT_FOR_SIM_TYPE) & 1); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_check_sim_available | +--------------------------------------------------------------------+ PURPOSE : The function checks whether the SIM is available or not. */ GLOBAL BOOL dat_check_sim_available (void) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_check_sim_available()"); return ((rr_data->ms_data.operation_mode >> SHIFT_FOR_SIM_INSERTED) & 1); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_vsd_bit_set | +--------------------------------------------------------------------+ PURPOSE : To set the send state variable V(S) and the corresponding bit for SAPI 0 messages on FACCH or SDCCH. The following possibilities are available: SET_ONLY: V(S) in incremented and the message bit is set RESET_ONLY: V(S) is initialized and the message bit is not set SET_AND_RESET: V(S) is initialized and the message bit is set. */ GLOBAL void dat_vsd_bit_set (T_L3_SDU *m_buf, UBYTE action) { static UBYTE vsd = 0; /* Send state variable V(S) */ UBYTE pd; /* protocol discriminator of the message */ UBYTE * msp; /* pointer to message type for setting the bit */ #ifdef REL99 UBYTE mscr = 0; /* variable to hold msc release version*/ #endif TRACE_FUNCTION ("dat_vsd_bit_set()"); /* * VSD shall be initialized */ if (action NEQ SET_ONLY) vsd = 0; /* * message bit shall be set */ if (action NEQ RESET_ONLY) { /* * calculate message type pointer and protocol discriminator */ TRACE_ASSERT( (m_buf->offset >> 3) < L3_SDU_BUF_SIZE ); msp = &m_buf->buffer[m_buf->offset >> 3]; pd = *msp++ & 0x0F; #ifdef REL99 /* * Get MSCR of the serving MSC */ get_msc_release_version(&mscr); TRACE_EVENT_P1("mscr (MSC release) version : 0x%X", mscr); #endif switch (pd) { case PD_SMS: /* * SMS on SDCCH is a SAPI 3 message and shall not be set. */ break; case PD_CC: case PD_SS: case PD_MM: #ifdef REL99 if (mscr EQ MSCR_99) { /* for MSC release R99 or above modulo 4 will be done. * SAPI 0 message: set bit 7th and 8th of MSG Type IE * and increment V(S) modulo 4. */ *msp |= (vsd++ << 6); vsd = vsd & 0x03; } else #endif { /* for MSC release R98 or old modulo 2 will be done. * SAPI 0 message: set bit if vsd is 1, else no effect * and increment V(S) modulo 2. */ *msp |= (vsd++ << 6); vsd &= 1; } } } } /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_begin_start_immediate_assign | +---------------------------------------------------------------------+ PURPOSE : initiate immediate assignment procedure by sending channel request */ GLOBAL void dat_begin_start_immediate_assign (UBYTE id_type, UBYTE chan_need) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_begin_start_immediate_assign()"); rr_data->page_identity_type = id_type; rr_data->ms_data.channel_needed = chan_need; dat_vsd_bit_set (&rr_data->ms_data.l3msg, RESET_ONLY); rr_data->sc_data.first_attempt = TRUE; rr_data->repeat_est = FALSE; dat_start_immediate_assign (ESTCS_PAGING); } /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_rr_release_ind | +---------------------------------------------------------------------+ PURPOSE : send RR_RELEASE_IND to MM */ GLOBAL void dat_rr_release_ind (USHORT relcs, UBYTE sapi) { PALLOC (rr_release_ind, RR_RELEASE_IND); rr_release_ind->cause = relcs; rr_release_ind->sapi = sapi; #ifdef GPRS dat_set_gprs_resump(rr_release_ind); #endif PSENDX (MM, rr_release_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_TIM | | STATE : code ROUTINE : dat_send_release_ind | +--------------------------------------------------------------------+ PURPOSE : Send RR_REELASE_IND to MM during the Access Procedure */ GLOBAL void dat_send_release_ind (USHORT cause) { GET_INSTANCE_DATA; TRACE_FUNCTION ("dat_send_release_ind()"); switch (rr_data->ms_data.establish_cause) { #ifdef GPRS case ESTCS_GPRS_1P: case ESTCS_GPRS_SB: case ESTCS_GPRS_PAGING: SET_STATE(STATE_GPRS, GPRS_PIM_BCCH); break; case ESTCS_PAGING: dat_rr_release_ind(RRCS_INT_NOT_PRESENT, SAPI_0); /* * After sending a release_ind RR shall consider that GRR leaves SUSPENDED state */ if(GPRS_SUSPENDED_BCCH EQ GET_STATE(STATE_GPRS)) { SET_STATE(STATE_GPRS,GPRS_PIM_BCCH); } else if(GPRS_SUSPENDED_PBCCH EQ GET_STATE(STATE_GPRS)) { SET_STATE(STATE_GPRS,GPRS_PIM_PBCCH); } #else case ESTCS_PAGING: #endif break; default: #ifdef GPRS /* * After sending a release_ind RR shall consider that GRR leaves SUSPENDED state */ if(GPRS_SUSPENDED_BCCH EQ GET_STATE(STATE_GPRS)) { SET_STATE(STATE_GPRS,GPRS_PIM_BCCH); } else if(GPRS_SUSPENDED_PBCCH EQ GET_STATE(STATE_GPRS)) { SET_STATE(STATE_GPRS,GPRS_PIM_PBCCH); } #endif if ( cause EQ RRCS_RND_ACC_FAIL ) { if (! IS_TIMER_ACTIVE (T3122)) { dat_rr_release_ind(RRCS_RND_ACC_FAIL, SAPI_0); } else { dat_rr_release_ind(RRCS_RND_ACC_DELAY, SAPI_0); } } else { dat_rr_release_ind(cause, SAPI_0); } break; } } /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_send_assign_fail_msg | +---------------------------------------------------------------------+ PURPOSE : send ASSIGNMENT FAILURE to network. */ void dat_send_assign_fail_msg(UBYTE cause) { GET_INSTANCE_DATA; MCAST (assign_fail, U_ASSIGN_FAIL); PALLOC_MSG (dl_reconnect_req, DL_RECONNECT_REQ, U_ASSIGN_FAIL); assign_fail->msg_type = U_ASSIGN_FAIL; assign_fail->rr_cause = cause; dat_code_prr_channel (&dl_reconnect_req->ch_type, &dl_reconnect_req->sapi, rr_data->sc_data.chan_desc.chan_type); /* * start reconnection in layer 2. */ for_dat_reconnect_req (dl_reconnect_req); } /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_send_rr_status_msg | +---------------------------------------------------------------------+ PURPOSE : send RR STATUS to network */ void dat_send_rr_status_msg(UBYTE cause) { GET_INSTANCE_DATA; MCAST (rr_status, B_RR_STATUS); PALLOC_MSG (dl_data_req, DL_DATA_REQ, B_RR_STATUS); /* * set channel type and SAPI */ dat_code_prr_channel (&dl_data_req->ch_type, &dl_data_req->sapi, rr_data->sc_data.chan_desc.chan_type); rr_status->msg_type = B_RR_STATUS; rr_status->rr_cause = cause; EM_RR_STATUS_SEND; for_dat_data_req (dl_data_req); } /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_send_handov_fail_msg | +---------------------------------------------------------------------+ PURPOSE : send HANDOVER FAILURE to network */ void dat_send_handov_fail_msg(UBYTE cause) { GET_INSTANCE_DATA; MCAST (handov_fail, U_HANDOV_FAIL); PALLOC_MSG (dl_reconnect_req, DL_RECONNECT_REQ, U_HANDOV_FAIL); /* * set channel type and sapi for the reconnection. */ dat_code_prr_channel (&dl_reconnect_req->ch_type, &dl_reconnect_req->sapi, rr_data->sc_data.chan_desc.chan_type); handov_fail->rr_cause = cause; handov_fail->msg_type = U_HANDOV_FAIL; /* * reconnect layer 2 link. */ for_dat_reconnect_req (dl_reconnect_req); } #if defined (REL99) && defined (TI_PS_FF_EMR) /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_update_emr_data | +---------------------------------------------------------------------+ PURPOSE : Updates the enhanced measurement parameters, other than BSIC and reporting priority. */ GLOBAL void dat_update_emr_rep_para(T_emp *p_em, T_enh_para_struct *p_enh) { p_enh->scale_order = p_em->scale_ord; if (p_em->v_serv_band_rep EQ TRUE) p_enh->servingband_rep = p_em->serv_band_rep; if (p_em->v_mr EQ TRUE ) p_enh->multiband_rep = p_em->mr; /* Update reporting thresholds and reporting offsets*/ if (p_em->v_report_900 EQ TRUE) { p_enh->enh_rep_data[0].rep_offset = p_em->report_900.rep_offset_900; p_enh->enh_rep_data[0].rep_offset = p_em->report_900.th_rep_900; } if (p_em->v_report_1800 EQ TRUE) { p_enh->enh_rep_data[1].rep_offset = p_em->report_1800.rep_offset_1800; p_enh->enh_rep_data[1].rep_offset = p_em->report_1800.th_rep_1800; } if (p_em->v_report_400 EQ TRUE) { p_enh->enh_rep_data[2].rep_offset = p_em->report_400.rep_offset_400; p_enh->enh_rep_data[2].rep_offset = p_em->report_400.th_rep_400; } if (p_em->v_report_1900 EQ TRUE) { p_enh->enh_rep_data[3].rep_offset = p_em->report_1900.rep_offset_1900; p_enh->enh_rep_data[3].rep_offset = p_em->report_1900.th_rep_1900; } if (p_em->v_report_850 EQ TRUE) { p_enh->enh_rep_data[4].rep_offset = p_em->report_850.rep_offset_850; p_enh->enh_rep_data[4].rep_offset = p_em->report_850.th_rep_850; } return; } /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_code_enh_measure_report | +---------------------------------------------------------------------+ PURPOSE : Forms enhanced measurement report and sends it to DL as a message with short PD. */ GLOBAL void dat_code_enh_measure_report(T_MPH_MEASUREMENT_IND *report) { GET_INSTANCE_DATA; UBYTE size_avail = MSG_SIZE_EMR - MAND_SIZE_EMR; MCAST (meas_emr, U_EMR); PALLOC_MSG (dl_data, DL_SHORT_UNITDATA_REQ, U_EMR); TRACE_FUNCTION ("dat_code_enh_measure_report()"); memset (&dl_data->sdu.buf[0], 0, dl_data->sdu.o_buf / BITS_PER_BYTE); /* initialize C-structure for the Uplink message */ memset (meas_emr, 0, sizeof (T_U_EMR)); meas_emr->msg_type = U_EMR; meas_emr->sl2h = SL2H_0; if (report->valid EQ TRUE) { T_enh_para_struct *src = &rr_data->sc_data.emr_data_current.enh_para; /* Fill the non-measurement paramaters */ meas_emr->ba_ind = rr_data->sc_data.ba_index; meas_emr->scale = report->scale_used; /* Now fill serving cell data */ if (report->rxlev_val NEQ 0) { meas_emr->v_scdata = TRUE; meas_emr->scdata.rxlev = report->rxlev_val; meas_emr->scdata.rxqual_full = report->rx_qual_full; meas_emr->scdata.mean_bep = report->mean_bep; meas_emr->scdata.cv_bep = report->cv_bep; meas_emr->scdata.nr_rcvd_bl = report->nbr_rcvd_blks; meas_emr->scdata.dtx_used = report->dtx; size_avail -= SC_INFO_SIZE_EMR; } /* Fill neighbour cell measurements */ if (report->ncells.no_of_ncells > 0) { UBYTE i; UBYTE j; UBYTE highest_index = 0; UBYTE index_0 = 1;/*To decrement size by 1 when index is 0*/ ULONG bit_map=0; meas_emr->em_rep.c_rep_q_arr = meas_emr->c_i_bsic_i = 0; for (i =0; i < report->ncells.no_of_ncells; i++ ) { j = report->nc_index[i]; /*Decide whether it is a valid BSIC cell or not*/ if ( j NEQ NOT_PRESENT_8BIT ) { /*This is an valid BSIC cell*/ /*Check the priority of the cell*/ if ( (src->rep_rate EQ REDUCED_REP_RATE) AND (src->enh_cell_list[j].rep_priority EQ REP_PRIOR_NORM )) { /*Proceed further only if the cell has not been included- in any report till now or if it's the time to include this cell in the report*/ if ( (rr_data->sc_data.rep_count[j] NEQ rr_data->sc_data.emr_count ) AND (rr_data->sc_data.rep_count[j] NEQ NOT_PRESENT_8BIT ) ) { bit_map |= (1<<i); continue; /* Include this cell at the end only if size is available*/ } } meas_emr->em_rep.rep_q_arr[j].rep_q = report->ncells.rx_lev[i]; if ( j > highest_index ) { /*When the place where the RXLEV has to be filled requires additional bits in bit map, then we have to account for these single bits and additional 6 bits for RXLEV*/ if (size_avail >= (j - highest_index)+6 + index_0 ) { /*This means we require atleast j-highest_index+6 bits in bit map to include this rxlev*/ /* 6 bits for RXLEV itself*/ size_avail = size_avail- (j-highest_index+6+index_0) ; highest_index = j; meas_emr->em_rep.c_rep_q_arr = j+1; /*counter is index+1*/ index_0 = 0; meas_emr->em_rep.rep_q_arr[j].v_rep_q = TRUE; rr_data->sc_data.rep_count[j] = rr_data->sc_data.emr_count; } } else if (size_avail >= 6 + index_0) { size_avail -= (6+index_0); /* size for bit map is already accounted for*/ meas_emr->em_rep.c_rep_q_arr = highest_index +1; index_0 = 0; meas_emr->em_rep.rep_q_arr[j].v_rep_q = TRUE; rr_data->sc_data.rep_count[j] = rr_data->sc_data.emr_count; } } /* if j NEQ NOT_PRESENT_8BIT */ else { /*This is a Invalid BSIC cell*/ /*fill in invalid BSIC list since cell is not present in the neighbour cell list. Here the index that needs to be filled is index of the ARFCN in BA(list)*/ if ( size_avail > NC_INVBSIC_EMR ) { meas_emr->i_bsic_i[meas_emr->c_i_bsic_i].ba_start_bsic = dat_get_ncell_pos (report->ncells.arfcn[i]); meas_emr->i_bsic_i[meas_emr->c_i_bsic_i].bsic = report->ncells.bsic[i] ; meas_emr->i_bsic_i[meas_emr->c_i_bsic_i++].rxlev = report->ncells.rx_lev[i]; size_avail -= NC_INVBSIC_EMR; } } if (size_avail < 6) /*no more cells can be included*/ break; } /* for 'i'*/ /*All the low priority cells have to be filled in valid BSIC bmp reporting, if still there's size available*/ i = 0; while ( (bit_map NEQ 0) AND (size_avail >= 6) ) { if ( ((bit_map >> i ) & (NOT_PRESENT_32BIT)) EQ TRUE ) { j = report->nc_index[i]; meas_emr->em_rep.rep_q_arr[j].rep_q = report->ncells.rx_lev[i]; if ( j > highest_index ) { /*When the place where the RXLEV has to be filled requires additional bits in bit map, then we have to account for these single bits and additional 6 bits for RXLEV*/ if (size_avail >= (j - highest_index)+6 + index_0 ) { /*This means we require atleast j-highest_index+6 bits in bit map to include this rxlev*/ /* 6 bits for RXLEV itself*/ size_avail = size_avail- (j-highest_index+6+index_0) ; highest_index = j; meas_emr->em_rep.c_rep_q_arr = j+1; /*counter is index+1*/ index_0 = 0; meas_emr->em_rep.rep_q_arr[j].v_rep_q = TRUE; rr_data->sc_data.rep_count[j] = rr_data->sc_data.emr_count; } } else if (size_avail >= 6 + index_0) { size_avail -= (6+index_0); /* size for bit map is already accounted for*/ meas_emr->em_rep.c_rep_q_arr = highest_index +1; index_0 = 0; meas_emr->em_rep.rep_q_arr[j].v_rep_q = TRUE; rr_data->sc_data.rep_count[j] = rr_data->sc_data.emr_count; } else break; bit_map = bit_map & ( ~ ((ULONG)( 1 << i))); /*reset the corresponding bit in bit map*/ } }/*while bit_map*/ if (meas_emr->em_rep.c_rep_q_arr > 0) meas_emr->v_em_rep = TRUE; if (meas_emr->c_i_bsic_i > 0) { meas_emr->v_i_bsic_i = TRUE; meas_emr->bsic_seen = report->bsic_seen; } } /* if 'report->ncells.no_of_ncells'*/ #if defined (REL99) && defined (TI_PS_FF_EMR) /*Fill the report with '0's till the end of message or upto 96 cells */ while ( (size_avail > 0) AND (meas_emr->em_rep.c_rep_q_arr < 96 ) ) { /* There are cells in GSM NC list for which bit map has to be set to '0' earlier memset takes care of this. we just need to set the counter appropriately*/ meas_emr->em_rep.c_rep_q_arr++; size_avail--; } #else if ( meas_emr->em_rep.c_rep_q_arr < src->num_valid_cells ) { /* There are cells in GSM NC list for which bit map has to be set to '0' earlier memset takes care of this. we just need to set the counter appropriately*/ meas_emr->em_rep.c_rep_q_arr = src->num_valid_cells; } dl_data->ccd_assist = meas_emr->em_rep.nnc = meas_emr->em_rep.c_rep_q_arr; #endif rr_data->sc_data.emr_count = (rr_data->sc_data.emr_count +1) & 0x03; /*MOD4 addition*/ } else { /* * measurement report from layer 1 is invalid */ TRACE_EVENT ("invalid meas_emr"); /*A dummy msg with all options as FALSE will go in this case, to network. may be useful to maintain periodicity*/ } /* Send the message to DL */ for_dat_spd_unitdata_req(dl_data); } #endif #if defined (TI_PS_FF_RTD) AND defined (REL99) /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_update_rtd_data | +---------------------------------------------------------------------+ PURPOSE : Updates the real time difference parameters received on MEAS_INFO message. */ GLOBAL void dat_update_rtd_data(T_D_MEAS_INF *p_mi,T_rr_enh_para *p_temp) { T_rtdd *rtdd_struct= &p_mi->rtdd; dat_update_common_rtd_struct(rtdd_struct,p_temp); } /* end dat_update_rtd_data()*/ /* +---------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : RR_DAT | | STATE : code ROUTINE : dat_update_common_rtd_struct | +---------------------------------------------------------------------+ PURPOSE : Common function called from for_store_rtd_data() to store rtd parameters received on si2 quater message and update the same on receiving meas_info message via function dat_update_rtd_data(). */ GLOBAL void dat_update_common_rtd_struct(T_rtdd *rtdd,T_rr_enh_para *p_temp) { UBYTE i,j,rtd_index,max_rtd_values; if(rtdd->v_rtdd6 EQ TRUE) { if(rtdd->rtdd6.v_ba_start_rtd EQ TRUE) rtd_index = rtdd->rtdd6.ba_start_rtd; else rtd_index = RTD_DEFAULT_INDEX; if( rtd_index < MAX_NR_OF_NCELL) { p_temp->enh_para.enh_cell_list[rtd_index].v_rtd = TRUE; max_rtd_values = rtdd->rtdd6.rtds6.c_rtd6 > MAX_NUM_OF_RTD_VALUES ? MAX_NUM_OF_RTD_VALUES : rtdd->rtdd6.rtds6.c_rtd6; for(i = 0;i < max_rtd_values;i++) p_temp->enh_para.enh_cell_list[rtd_index].rtd[i] = rtdd->rtdd6.rtds6.rtd6[i]; p_temp->enh_para.enh_cell_list[rtd_index].c_rtd= max_rtd_values; } /*if*/ for(j = 0;j < rtdd->rtdd6.c_rtds6_add;j++) { rtd_index++; if( rtd_index < MAX_NR_OF_NCELL) { p_temp->enh_para.enh_cell_list[rtd_index].v_rtd = TRUE; max_rtd_values = rtdd->rtdd6.rtds6_add[j].c_rtd6 > MAX_NUM_OF_RTD_VALUES ? MAX_NUM_OF_RTD_VALUES : rtdd->rtdd6.rtds6_add[j].c_rtd6; for(i = 0;i < max_rtd_values;i++) p_temp->enh_para.enh_cell_list[rtd_index].rtd[i] = rtdd->rtdd6.rtds6_add[j].rtd6[i]; p_temp->enh_para.enh_cell_list[rtd_index].c_rtd= max_rtd_values; } /*if*/ } /*for*/ } /*if*/ if(rtdd->v_rtdd12 EQ TRUE) { if(rtdd->rtdd12.v_ba_start_rtd EQ TRUE) rtd_index = rtdd->rtdd12.ba_start_rtd; else rtd_index = RTD_DEFAULT_INDEX; if( rtd_index < MAX_NR_OF_NCELL) { p_temp->enh_para.enh_cell_list[rtd_index].v_rtd = TRUE; max_rtd_values = rtdd->rtdd12.rtds12.c_rtd12 > MAX_NUM_OF_RTD_VALUES ? MAX_NUM_OF_RTD_VALUES: rtdd->rtdd12.rtds12.c_rtd12; for(i = 0;i < max_rtd_values;i++) { p_temp->enh_para.enh_cell_list[rtd_index].rtd[i] =RTD_12BIT; p_temp->enh_para.enh_cell_list[rtd_index].rtd[i] |= rtdd->rtdd12.rtds12.rtd12[i]; } /*for*/ p_temp->enh_para.enh_cell_list[rtd_index].c_rtd= max_rtd_values; } /*if*/ for(j = 0;j < rtdd->rtdd12.c_rtds12_add;j++) { rtd_index++; if(rtd_index < MAX_NR_OF_NCELL) { p_temp->enh_para.enh_cell_list[rtd_index].v_rtd = TRUE; max_rtd_values = rtdd->rtdd12.rtds12_add[j].c_rtd12 > MAX_NUM_OF_RTD_VALUES ? MAX_NUM_OF_RTD_VALUES : rtdd->rtdd12.rtds12_add[j].c_rtd12; for(i = 0;i < max_rtd_values;i++) { p_temp->enh_para.enh_cell_list[rtd_index].rtd[i] = RTD_12BIT; p_temp->enh_para.enh_cell_list[rtd_index].rtd[i] |= rtdd->rtdd12.rtds12_add[j].rtd12[i]; } /*for*/ p_temp->enh_para.enh_cell_list[rtd_index].c_rtd= max_rtd_values; } /*if*/ } /*for*/ } /*if*/ } /* end of dat_update_common_rtd_struct() */ #endif /* #if defined (TI_PS_FF_RTD) AND defined (REL99) */ #endif