#include <osmocom/bb/mobile/vty.h>
static void start_rr_t_meas(struct gsm48_rrlayer *rr, int sec, int micro);
-static void stop_rr_t_meas(struct gsm48_rrlayer *rr);
static void stop_rr_t_starting(struct gsm48_rrlayer *rr);
static void stop_rr_t3124(struct gsm48_rrlayer *rr);
static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg);
static int gsm48_rr_tx_meas_rep(struct osmocom_ms *ms);
static int gsm48_rr_set_mode(struct osmocom_ms *ms, uint8_t chan_nr,
uint8_t mode);
+static int gsm48_rr_rel_cnf(struct osmocom_ms *ms, struct msgb *msg);
/*
* support
static uint8_t gsm48_rr_check_mode(struct osmocom_ms *ms, uint8_t chan_nr,
uint8_t mode)
{
- struct gsm_support *sup = &ms->support;
+ struct gsm_settings *set = &ms->settings;
uint8_t ch_type, ch_subch, ch_ts;
/* only complain if we use TCH/F or TCH/H */
break;
case GSM48_CMODE_SPEECH_V1:
if (ch_type == RSL_CHAN_Bm_ACCHs) {
- if (!sup->full_v1) {
+ if (!set->full_v1) {
LOGP(DRR, LOGL_NOTICE, "Not supporting "
"full-rate speech V1\n");
return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
}
LOGP(DRR, LOGL_INFO, "Mode: full-rate speech V1\n");
} else {
- if (!sup->half_v1) {
+ if (!set->half_v1) {
LOGP(DRR, LOGL_NOTICE, "Not supporting "
"half-rate speech V1\n");
return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
break;
case GSM48_CMODE_SPEECH_EFR:
if (ch_type == RSL_CHAN_Bm_ACCHs) {
- if (!sup->full_v2) {
+ if (!set->full_v2) {
LOGP(DRR, LOGL_NOTICE, "Not supporting "
"full-rate speech V2\n");
return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
break;
case GSM48_CMODE_SPEECH_AMR:
if (ch_type == RSL_CHAN_Bm_ACCHs) {
- if (!sup->full_v3) {
+ if (!set->full_v3) {
LOGP(DRR, LOGL_NOTICE, "Not supporting "
"full-rate speech V3\n");
return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
}
LOGP(DRR, LOGL_INFO, "Mode: full-rate speech V3\n");
} else {
- if (!sup->half_v3) {
+ if (!set->half_v3) {
LOGP(DRR, LOGL_NOTICE, "Not supporting "
"half-rate speech V3\n");
return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
/* release dedicated mode, if any */
l1ctl_tx_dm_rel_req(rr->ms);
+ rr->ms->meas.rl_fail = 0;
rr->dm_est = 0;
l1ctl_tx_reset_req(rr->ms, L1CTL_RES_T_FULL);
/* free establish message, if any */
if (rr->dm_est)
gsm48_rr_tx_meas_rep(rr->ms);
- memset(meas, 0, sizeof(*meas));
+ meas->frames = meas->snr = meas->berr = meas->rxlev = 0;
start_rr_t_meas(rr, 1, 0);
}
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm_support *sup = &ms->support;
+ struct gsm_settings *set = &ms->settings;
struct gsm48_hdr *gh = msgb_l3(msg);
struct gsm48_cip_mode_cmd *cm = (struct gsm48_cip_mode_cmd *)gh->data;
int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*cm);
}
/* check if we actually support this cipher */
- if (sc && ((alg_id == GSM_CIPHER_A5_1 && !sup->a5_1)
- || (alg_id == GSM_CIPHER_A5_2 && !sup->a5_2)
- || (alg_id == GSM_CIPHER_A5_3 && !sup->a5_3)
- || (alg_id == GSM_CIPHER_A5_4 && !sup->a5_4)
- || (alg_id == GSM_CIPHER_A5_5 && !sup->a5_5)
- || (alg_id == GSM_CIPHER_A5_6 && !sup->a5_6)
- || (alg_id == GSM_CIPHER_A5_7 && !sup->a5_7))) {
+ if (sc && ((alg_id == GSM_CIPHER_A5_1 && !set->a5_1)
+ || (alg_id == GSM_CIPHER_A5_2 && !set->a5_2)
+ || (alg_id == GSM_CIPHER_A5_3 && !set->a5_3)
+ || (alg_id == GSM_CIPHER_A5_4 && !set->a5_4)
+ || (alg_id == GSM_CIPHER_A5_5 && !set->a5_5)
+ || (alg_id == GSM_CIPHER_A5_6 && !set->a5_6)
+ || (alg_id == GSM_CIPHER_A5_7 && !set->a5_7))) {
LOGP(DRR, LOGL_NOTICE, "algo not supported\n");
return gsm48_rr_tx_rr_status(ms,
GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
static int gsm48_rr_enc_cm3(struct osmocom_ms *ms, uint8_t *buf, uint8_t *len)
{
struct gsm_support *sup = &ms->support;
+ struct gsm_settings *set = &ms->settings;
struct bitvec bv;
memset(&bv, 0, sizeof(bv));
/* spare bit */
bitvec_set_bit(&bv, 0);
/* band 3 supported */
- if (sup->dcs_1800)
+ if (set->dcs)
bitvec_set_bit(&bv, ONE);
else
bitvec_set_bit(&bv, ZERO);
/* band 2 supported */
- if (sup->e_gsm || sup->r_gsm)
+ if (set->e_gsm || set->r_gsm)
bitvec_set_bit(&bv, ONE);
else
bitvec_set_bit(&bv, ZERO);
/* band 1 supported */
- if (sup->p_gsm && !(sup->e_gsm || sup->r_gsm))
+ if (set->p_gsm && !(set->e_gsm || set->r_gsm))
bitvec_set_bit(&bv, ONE);
else
bitvec_set_bit(&bv, ZERO);
/* a5 bits */
- if (sup->a5_7)
+ if (set->a5_7)
bitvec_set_bit(&bv, ONE);
else
bitvec_set_bit(&bv, ZERO);
- if (sup->a5_6)
+ if (set->a5_6)
bitvec_set_bit(&bv, ONE);
else
bitvec_set_bit(&bv, ZERO);
- if (sup->a5_5)
+ if (set->a5_5)
bitvec_set_bit(&bv, ONE);
else
bitvec_set_bit(&bv, ZERO);
- if (sup->a5_4)
+ if (set->a5_4)
bitvec_set_bit(&bv, ONE);
else
bitvec_set_bit(&bv, ZERO);
/* radio capability */
- if (sup->dcs_1800 && !sup->p_gsm && !(sup->e_gsm || sup->r_gsm)) {
+ if (set->dcs && !set->p_gsm && !(set->e_gsm || set->r_gsm)) {
/* dcs only */
bitvec_set_uint(&bv, 0, 4);
- bitvec_set_uint(&bv, sup->dcs_capa, 4);
+ bitvec_set_uint(&bv, set->class_dcs, 4);
} else
- if (sup->dcs_1800 && (sup->p_gsm || (sup->e_gsm || sup->r_gsm))) {
+ if (set->dcs && (set->p_gsm || (set->e_gsm || set->r_gsm))) {
/* dcs */
- bitvec_set_uint(&bv, sup->dcs_capa, 4);
+ bitvec_set_uint(&bv, set->class_dcs, 4);
/* low band */
- bitvec_set_uint(&bv, sup->low_capa, 4);
+ bitvec_set_uint(&bv, set->class_900, 4);
} else {
/* low band only */
bitvec_set_uint(&bv, 0, 4);
- bitvec_set_uint(&bv, sup->low_capa, 4);
+ bitvec_set_uint(&bv, set->class_900, 4);
}
/* r support */
- if (sup->r_gsm) {
+ if (set->r_gsm) {
bitvec_set_bit(&bv, ONE);
- bitvec_set_uint(&bv, sup->r_capa, 3);
+ bitvec_set_uint(&bv, set->class_900, 3);
} else {
bitvec_set_bit(&bv, ZERO);
}
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm_support *sup = &ms->support;
+ struct gsm_settings *set = &ms->settings;
if (rr->cd_now.arfcn >= 512 && rr->cd_now.arfcn <= 885)
- cm->pwr_lev = sup->pwr_lev_1800;
+ cm->pwr_lev = set->class_dcs - 1;
else
- cm->pwr_lev = sup->pwr_lev_900;
- cm->a5_1 = !sup->a5_1;
+ cm->pwr_lev = set->class_900 - 1;
+ cm->a5_1 = !set->a5_1;
cm->es_ind = sup->es_ind;
cm->rev_lev = sup->rev_lev;
- cm->fc = (sup->r_gsm || sup->e_gsm);
+ cm->fc = (set->r_gsm || set->e_gsm);
cm->vgcs = sup->vgcs;
cm->vbs = sup->vbs;
- cm->sm_cap = sup->sms_ptp;
+ cm->sm_cap = set->sms_ptp;
cm->ss_scr = sup->ss_ind;
cm->ps_cap = sup->ps_cap;
- cm->a5_2 = sup->a5_2;
- cm->a5_3 = sup->a5_3;
+ cm->a5_2 = set->a5_2;
+ cm->a5_3 = set->a5_3;
cm->cmsp = sup->cmsp;
cm->solsa = sup->solsa;
cm->lcsva_cap = sup->lcsva;
static int gsm48_rr_tx_cm_change(struct osmocom_ms *ms)
{
struct gsm_support *sup = &ms->support;
+ struct gsm_settings *set = &ms->settings;
struct msgb *nmsg;
struct gsm48_hdr *gh;
struct gsm48_cm_change *cc;
gsm48_rr_enc_cm2(ms, &cc->cm2);
/* classmark 3 */
- if (sup->dcs_1800 || sup->e_gsm || sup->r_gsm
- || sup->a5_7 || sup->a5_6 || sup->a5_5 || sup->a5_4
+ if (set->dcs || set->e_gsm || set->r_gsm
+ || set->a5_7 || set->a5_6 || set->a5_5 || set->a5_4
|| sup->ms_sup
|| sup->ucs2_treat
|| sup->ext_meas || sup->meas_cap
/* start random access */
static int gsm48_rr_chan_req(struct osmocom_ms *ms, int cause, int paging)
{
- struct gsm_support *sup = &ms->support;
+ struct gsm_settings *set = &ms->settings;
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm322_cellsel *cs = &ms->cellsel;
struct gsm48_sysinfo *s = cs->si;
chan_req_val);
break;
case RR_EST_CAUSE_ANS_PAG_TCH_F:
- switch (sup->ch_cap) {
+ switch (set->ch_cap) {
case GSM_CAP_SDCCH:
chan_req_mask = 0x0f;
chan_req_val = 0x10;
chan_req_val);
break;
case RR_EST_CAUSE_ANS_PAG_TCH_ANY:
- switch (sup->ch_cap) {
+ switch (set->ch_cap) {
case GSM_CAP_SDCCH:
chan_req_mask = 0x0f;
chan_req_val = 0x10;
*/
/* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */
-static int decode_freq_list(struct gsm_support *sup,
+static int decode_freq_list(struct gsm_settings *set,
struct gsm_sysinfo_freq *f, uint8_t *cd, uint8_t len, uint8_t mask,
uint8_t frqt)
{
/* only Bit map 0 format for P-GSM */
if ((cd[0] & 0xc0 & mask) != 0x00 &&
- (sup->p_gsm && !sup->e_gsm && !sup->r_gsm && !sup->dcs_1800))
+ (set->p_gsm && !set->e_gsm && !set->r_gsm && !set->dcs))
return 0;
return gsm48_decode_freq_list(f, cd, len, mask, frqt);
LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 1\n");
/* Cell Channel Description */
- decode_freq_list(&ms->support, s->freq,
+ decode_freq_list(&ms->settings, s->freq,
si->cell_channel_description,
sizeof(si->cell_channel_description), 0xce, FREQ_TYPE_SERV);
/* RACH Control Parameter */
/* Neighbor Cell Description */
s->nb_ext_ind_si2 = (si->bcch_frequency_list[0] >> 6) & 1;
s->nb_ba_ind_si2 = (si->bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->support, s->freq, si->bcch_frequency_list,
+ decode_freq_list(&ms->settings, s->freq, si->bcch_frequency_list,
sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_NCELL_2);
/* NCC Permitted */
s->nb_ncc_permitted_si2 = si->ncc_permitted;
/* Neighbor Cell Description */
s->nb_ext_ind_si2bis = (si->bcch_frequency_list[0] >> 6) & 1;
s->nb_ba_ind_si2bis = (si->bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->support, s->freq,
+ decode_freq_list(&ms->settings, s->freq,
si->bcch_frequency_list,
sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_NCELL_2bis);
/* RACH Control Parameter */
/* Neighbor Cell Description 2 */
s->nb_multi_rep_si2ter = (si->ext_bcch_frequency_list[0] >> 6) & 3;
s->nb_ba_ind_si2ter = (si->ext_bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->support, s->freq,
+ decode_freq_list(&ms->settings, s->freq,
si->ext_bcch_frequency_list,
sizeof(si->ext_bcch_frequency_list), 0x8e,
FREQ_TYPE_NCELL_2ter);
/* Neighbor Cell Description */
s->nb_ext_ind_si5 = (si->bcch_frequency_list[0] >> 6) & 1;
s->nb_ba_ind_si5 = (si->bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->support, s->freq, si->bcch_frequency_list,
+ decode_freq_list(&ms->settings, s->freq, si->bcch_frequency_list,
sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5);
s->si5 = 1;
/* Neighbor Cell Description */
s->nb_ext_ind_si5bis = (si->bcch_frequency_list[0] >> 6) & 1;
s->nb_ba_ind_si5bis = (si->bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->support, s->freq, si->bcch_frequency_list,
+ decode_freq_list(&ms->settings, s->freq, si->bcch_frequency_list,
sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5bis);
s->si5bis = 1;
/* Neighbor Cell Description */
s->nb_multi_rep_si5ter = (si->bcch_frequency_list[0] >> 6) & 3;
s->nb_ba_ind_si5ter = (si->bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->support, s->freq, si->bcch_frequency_list,
+ decode_freq_list(&ms->settings, s->freq, si->bcch_frequency_list,
sizeof(si->bcch_frequency_list), 0x8e, FREQ_TYPE_REP_5ter);
s->si5ter = 1;
/* NOTE: pseudo length is not in this structure, so we skip */
struct gsm48_system_information_type_6 *si = msgb_l3(msg) + 1;
struct gsm48_sysinfo *s = ms->cellsel.si;
+ struct rx_meas_stat *meas = &ms->meas;
int payload_len = msgb_l3len(msg) - sizeof(*si) - 1;
if (!s) {
"lac 0x%04x SACCH-timeout %d)\n", gsm_print_mcc(s->mcc),
gsm_print_mnc(s->mnc), s->lac, s->sacch_radio_link_timeout);
+ meas->rl_fail = meas->s = s->sacch_radio_link_timeout;
+ LOGP(DRR, LOGL_INFO, "using (new) SACCH timeout %d\n", meas->rl_fail);
s->si6 = 1;
return gsm48_new_sysinfo(ms, si->system_information);
struct gsm48_sysinfo *s = ms->cellsel.si;
struct rx_meas_stat *meas = &ms->meas;
uint8_t ch_type, ch_subch, ch_ts;
+ uint8_t timeout = 64;
/* setting (new) timing advance */
LOGP(DRR, LOGL_INFO, "setting indicated TA %d (actual TA %d)\n",
l1ctl_tx_param_req(ms, cd->ind_ta - set->alter_delay,
(set->alter_tx_power) ? set->alter_tx_power_value
: cd->ind_tx_power);
+
+ /* reset measurement and link timeout */
+ meas->ds_fail = 0;
+ if (s) {
+ if (s->sacch_radio_link_timeout) {
+ timeout = s->sacch_radio_link_timeout;
+ LOGP(DRR, LOGL_INFO, "using last SACCH timeout %d\n",
+ timeout);
+ } else if (s->bcch_radio_link_timeout) {
+ timeout = s->bcch_radio_link_timeout;
+ LOGP(DRR, LOGL_INFO, "using last BCCH timeout %d\n",
+ timeout);
+ }
+ }
+ meas->rl_fail = meas->s = timeout;
+
/* setting initial (invalid) measurement report, resetting SI5* */
if (s) {
memset(s->si5_msg, 0, sizeof(s->si5_msg));
memset(s->si5b_msg, 0, sizeof(s->si5b_msg));
memset(s->si5t_msg, 0, sizeof(s->si5t_msg));
- memset(meas, 0, sizeof(*meas));
}
+ meas->frames = meas->snr = meas->berr = meas->rxlev = 0;
rr->meas.nc_num = 0;
stop_rr_t_meas(rr);
start_rr_t_meas(rr, 1, 0);
/* establish */
LOGP(DRR, LOGL_INFO, "establishing channel in dedicated mode\n");
rsl_dec_chan_nr(cd->chan_nr, &ch_type, &ch_subch, &ch_ts);
- LOGP(DRR, LOGL_INFO, " Channel type %d, subch %d, ts %d, mode %d\n",
- ch_type, ch_subch, ch_ts, cd->mode);
+ LOGP(DRR, LOGL_INFO, " Channel type %d, subch %d, ts %d, mode %d, "
+ "cipher %d\n", ch_type, ch_subch, ch_ts, cd->mode,
+ rr->cipher_type + 1);
if (cd->h)
l1ctl_tx_dm_est_req_h1(ms, cd->maio, cd->hsn,
- ma, ma_len, cd->chan_nr, cd->tsc);
+ ma, ma_len, cd->chan_nr, cd->tsc, cd->mode);
else
- l1ctl_tx_dm_est_req_h0(ms, cd->arfcn, cd->chan_nr, cd->tsc);
+ l1ctl_tx_dm_est_req_h0(ms, cd->arfcn, cd->chan_nr, cd->tsc,
+ cd->mode);
rr->dm_est = 1;
if (rr->cipher_on)
l1ctl_tx_crypto_req(ms, rr->cipher_type + 1, subscr->key, 8);
- gsm48_rr_set_mode(ms, cd->chan_nr, cd->mode);
-
return 0;
}
struct msgb *nmsg;
struct gsm48_rr_hdr *nrrh;
+ /* switch back to old channel, if modify/ho failed */
+ switch (rr->modify_state) {
+ case GSM48_RR_MOD_ASSIGN:
+ case GSM48_RR_MOD_HANDO:
+ /* channel is deactivate there */
+ return gsm48_rr_rel_cnf(ms, msg);
+ case GSM48_RR_MOD_ASSIGN_RESUME:
+ case GSM48_RR_MOD_HANDO_RESUME:
+ rr->modify_state = GSM48_RR_MOD_NONE;
+ break;
+ }
+
LOGP(DSUM, LOGL_INFO, "Radio link is released\n");
/* send inication to upper layer */
/* RR_CAUSE */
ac->rr_cause = cause;
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg);
}
/* 9.1.4 sending ASSIGNMENT FAILURE */
-static int gsm48_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause)
+static int gsm48_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause,
+ uint8_t rsl_prim)
{
struct msgb *nmsg;
struct gsm48_hdr *gh;
/* RR_CAUSE */
af->rr_cause = cause;
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+ return gsm48_send_rsl(ms, rsl_prim, nmsg);
}
/* 9.1.2 ASSIGNMENT COMMAND is received */
/* check if channels are valid */
cause = gsm48_rr_check_mode(ms, cda->chan_nr, cda->mode);
if (cause)
- return gsm48_rr_tx_ass_fail(ms, cause);
+ return gsm48_rr_tx_ass_fail(ms, cause, RSL_MT_DATA_REQ);
if (before_time) {
cause = gsm48_rr_render_ma(ms, cdb, ma, &ma_len);
if (cause)
- return gsm48_rr_tx_ass_fail(ms, cause);
+ return gsm48_rr_tx_ass_fail(ms, cause, RSL_MT_DATA_REQ);
}
cause = gsm48_rr_render_ma(ms, cda, ma, &ma_len);
if (cause)
- return gsm48_rr_tx_ass_fail(ms, cause);
-
-
-#if 0
- if (not supported) {
- LOGP(DRR, LOGL_NOTICE, "New channel is not supported.\n");
- return GSM48_RR_CAUSE_CHAN_MODE_UNACCEPT;
- }
-#endif
+ return gsm48_rr_tx_ass_fail(ms, cause, RSL_MT_DATA_REQ);
#ifdef TEST_FREQUENCY_MOD
LOGP(DRR, LOGL_INFO, " TESTING: frequency modify ASS.CMD\n");
// FIXME: mobile observed time
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg);
}
/* 9.1.4 sending HANDOVER FAILURE */
-static int gsm48_rr_tx_hando_fail(struct osmocom_ms *ms, uint8_t cause)
+static int gsm48_rr_tx_hando_fail(struct osmocom_ms *ms, uint8_t cause,
+ uint8_t rsl_prim)
{
struct msgb *nmsg;
struct gsm48_hdr *gh;
/* RR_CAUSE */
hf->rr_cause = cause;
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+ return gsm48_send_rsl(ms, rsl_prim, nmsg);
}
/* receiving HANDOVER COMMAND message (9.1.15) */
rr->chan_req_val = ho->ho_ref;
rr->chan_req_mask = 0x00;
+ tlv_parse(&tp, &gsm48_rr_att_tlvdef, ho->data, payload_len, 0, 0);
+
/* sync ind */
if (TLVP_PRESENT(&tp, GSM48_IE_SYNC_IND)) {
gsm48_decode_sync_ind(rr, (struct gsm48_sync_ind *)
rr->hando_sync_ind, rr->hando_rot, rr->hando_nci);
}
- tlv_parse(&tp, &gsm48_rr_att_tlvdef, ho->data, payload_len, 0, 0);
-
/* decode channel description (before time) */
if (TLVP_PRESENT(&tp, GSM48_IE_CH_DESC_1_BEFORE)) {
struct gsm48_chan_desc *ccd = (struct gsm48_chan_desc *)
if (before_time) {
cause = gsm48_rr_render_ma(ms, cdb, ma, &ma_len);
if (cause)
- return gsm48_rr_tx_hando_fail(ms, cause);
+ return gsm48_rr_tx_hando_fail(ms, cause, RSL_MT_DATA_REQ);
}
cause = gsm48_rr_render_ma(ms, cda, ma, &ma_len);
if (cause)
- return gsm48_rr_tx_hando_fail(ms, cause);
+ return gsm48_rr_tx_hando_fail(ms, cause, RSL_MT_DATA_REQ);
#if 0
LOGP(DRR, LOGL_INFO, "data link is resumed\n");
- switch (rr->modify_state) {
- case GSM48_RR_MOD_ASSIGN:
- gsm48_rr_tx_ass_cpl(ms, GSM48_RR_CAUSE_NORMAL);
- break;
- case GSM48_RR_MOD_HANDO:
- gsm48_rr_tx_hando_cpl(ms, GSM48_RR_CAUSE_NORMAL);
- break;
- case GSM48_RR_MOD_ASSIGN_RESUME:
- gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
- break;
- case GSM48_RR_MOD_HANDO_RESUME:
- gsm48_rr_tx_hando_fail(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
- break;
- }
-
/* transmit queued frames during ho / ass transition */
gsm48_rr_dequeue_down(ms);
struct gsm48_rrlayer *rr = &ms->rrlayer;
if (rr->modify_state) {
- struct msgb *nmsg;
uint16_t ma[64];
uint8_t ma_len;
LOGP(DRR, LOGL_INFO, "suspension coplete, leaving dedicated "
"mode\n");
l1ctl_tx_dm_rel_req(ms);
+ ms->meas.rl_fail = 0;
rr->dm_est = 0;
l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED);
/* send DL-RESUME REQUEST */
LOGP(DRR, LOGL_INFO, "request resume of data link\n");
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg);
+ switch (rr->modify_state) {
+ case GSM48_RR_MOD_ASSIGN:
+ gsm48_rr_tx_ass_cpl(ms, GSM48_RR_CAUSE_NORMAL);
+ break;
+ case GSM48_RR_MOD_HANDO:
+ gsm48_rr_tx_hando_cpl(ms, GSM48_RR_CAUSE_NORMAL);
+ break;
+ }
#ifdef TODO
/* trigger RACH */
/* check if camping */
if (cs->state != GSM322_C3_CAMPED_NORMALLY
&& rrh->cause != RR_EST_CAUSE_EMERGENCY) {
- LOGP(DRR, LOGL_INFO, "Not camping normally, rejecting!\n");
+ LOGP(DRR, LOGL_INFO, "Not camping normally, rejecting! "
+ "(cs->state = %d)\n", cs->state);
cause = RR_REL_CAUSE_EMERGENCY_ONLY;
goto reject;
}
if (cs->state != GSM322_C3_CAMPED_NORMALLY
&& cs->state != GSM322_C7_CAMPED_ANY_CELL) {
- LOGP(DRR, LOGL_INFO, "Not camping, rejecting!\n");
+ LOGP(DRR, LOGL_INFO, "Not camping, rejecting! "
+ "(cs->state = %d)\n", cs->state);
cause = RR_REL_CAUSE_TRY_LATER;
goto reject;
}
/* unit data from layer 2 to RR layer */
static int gsm48_rr_unit_data_ind(struct osmocom_ms *ms, struct msgb *msg)
{
- struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm322_cellsel *cs = &ms->cellsel;
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
struct tlv_parsed tv;
&& cs->ccch_state != GSM322_CCCH_ST_DATA)
return -EINVAL;
- /* when camping, start/reset loss timer */
- if (cs->state == GSM322_C3_CAMPED_NORMALLY
- || cs->state == GSM322_C7_CAMPED_ANY_CELL) {
- struct gsm48_sysinfo *s = &ms->cellsel.sel_si;
-#ifdef TODO
- set radio link timeout on layer 1
- it is the number of subsequent BCCH blocks. (about 1/4 seconds)
-#else
- /* use maximu loss timer, if to value is not available yet */
- start_loss_timer(cs, ((rr->state == GSM48_RR_ST_DEDICATED)
- ? ((s->sacch_radio_link_timeout) ? : 64)
- : s->bcch_radio_link_timeout) / 4, 0);
-#endif
- }
-
/* temporary moved here until confirm is fixed */
if (cs->ccch_state != GSM322_CCCH_ST_DATA) {
LOGP(DCS, LOGL_INFO, "Channel provides data.\n");
return gsm48_rr_rx_pch_agch(ms, msg);
case RSL_CHAN_BCCH:
return gsm48_rr_rx_bcch(ms, msg);
+ case RSL_CHAN_Bm_ACCHs:
+ case RSL_CHAN_Lm_ACCHs:
case RSL_CHAN_SDCCH4_ACCH:
- return gsm48_rr_rx_acch(ms, msg);
case RSL_CHAN_SDCCH8_ACCH:
return gsm48_rr_rx_acch(ms, msg);
default:
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct msgb *nmsg;
struct gsm48_rr_hdr *nrrh;
+ uint8_t cause = RR_REL_CAUSE_NORMAL;
+ uint16_t ma[64];
+ uint8_t ma_len;
+
+ /* switch back to old channel, if modify/ho failed */
+ switch (rr->modify_state) {
+ case GSM48_RR_MOD_ASSIGN:
+ case GSM48_RR_MOD_HANDO:
+ /* deactivate channel */
+ l1ctl_tx_dm_rel_req(ms);
+ ms->meas.rl_fail = 0;
+ rr->dm_est = 0;
+ l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED);
+
+ /* get old channel description */
+ memcpy(&rr->cd_now, &rr->cd_last, sizeof(rr->cd_now));
+
+ /* render and change radio to old channel */
+ gsm48_rr_render_ma(ms, &rr->cd_now, ma, &ma_len);
+ gsm48_rr_activate_channel(ms, &rr->cd_now, ma, ma_len);
+
+ /* re-establish old link */
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ if (rr->modify_state == GSM48_RR_MOD_ASSIGN) {
+ rr->modify_state = GSM48_RR_MOD_ASSIGN_RESUME;
+ return gsm48_rr_tx_ass_fail(ms,
+ GSM48_RR_CAUSE_ABNORMAL_UNSPEC,
+ RSL_MT_RECON_REQ);
+ } else {
+ rr->modify_state = GSM48_RR_MOD_HANDO_RESUME;
+ return gsm48_rr_tx_hando_fail(ms,
+ GSM48_RR_CAUSE_ABNORMAL_UNSPEC,
+ RSL_MT_RECON_REQ);
+ }
+ /* returns above */
+ case GSM48_RR_MOD_ASSIGN_RESUME:
+ case GSM48_RR_MOD_HANDO_RESUME:
+ rr->modify_state = GSM48_RR_MOD_NONE;
+ cause = RR_REL_CAUSE_LINK_FAILURE;
+ break;
+ }
- LOGP(DSUM, LOGL_INFO, "Requesting channel aborted\n");
+ LOGP(DSUM, LOGL_INFO, "Requested channel aborted\n");
/* stop T3211 if running */
stop_rr_t3110(rr);
if (!nmsg)
return -ENOMEM;
nrrh = (struct gsm48_rr_hdr *)nmsg->data;
- nrrh->cause = RR_REL_CAUSE_NORMAL;
+ nrrh->cause = cause;
gsm48_rr_upmsg(ms, nmsg);
/* return idle */
struct gsm48_rr_hdr *nrrh;
uint8_t *mode;
uint8_t cause = rllh->data[2];
- uint16_t ma[64];
- uint8_t ma_len;
switch (cause) {
case RLL_CAUSE_SEQ_ERR:
mode[1] = 1; /* local release */
gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg);
- /* deactivate channel */
- l1ctl_tx_dm_rel_req(ms);
- rr->dm_est = 0;
- l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED);
-
- switch (rr->modify_state) {
- case GSM48_RR_MOD_ASSIGN:
- case GSM48_RR_MOD_HANDO:
- if (rr->modify_state == GSM48_RR_MOD_ASSIGN)
- rr->modify_state = GSM48_RR_MOD_ASSIGN_RESUME;
- else
- rr->modify_state = GSM48_RR_MOD_HANDO_RESUME;
-
- /* get old channel description */
- memcpy(&rr->cd_now, &rr->cd_last, sizeof(rr->cd_now));
-
- /* render and change radio to old channel */
- gsm48_rr_render_ma(ms, &rr->cd_now, ma, &ma_len);
- gsm48_rr_activate_channel(ms, &rr->cd_now, ma, ma_len);
-
- /* re-establish old link */
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- return gsm48_send_rsl(ms, RSL_MT_RECON_REQ, nmsg);
- case GSM48_RR_MOD_ASSIGN_RESUME:
- case GSM48_RR_MOD_HANDO_RESUME:
- rr->modify_state = GSM48_RR_MOD_NONE;
- break;
- }
+ /* in case of modify/hando: wait for confirm */
+ if (rr->modify_state)
+ return 0;
/* send abort ind to upper layer */
nmsg = gsm48_rr_msgb_alloc(GSM48_RR_ABORT_IND);
{SBIT(GSM48_RR_ST_REL_PEND),
RSL_MT_REL_CONF, gsm48_rr_rel_cnf},
+ /* reconnect */
+ {SBIT(GSM48_RR_ST_CONN_PEND) |
+ SBIT(GSM48_RR_ST_DEDICATED),
+ RSL_MT_REL_CONF, gsm48_rr_rel_cnf},
+
/* suspenion */
{SBIT(GSM48_RR_ST_DEDICATED),
RSL_MT_SUSP_CONF, gsm48_rr_susp_cnf_dedicated},