X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=src%2Fhost%2Flayer23%2Fsrc%2Fmobile%2Fgsm48_rr.c;h=e2418ccf7f6500b6036b172f1150d5384e4ee1f6;hb=b349e38838d6df853661ceefdfa1a007d2d5b449;hp=0e4c2dea909d662baf037c2c7cb56224e8e27189;hpb=4337d3bb2e2a0d205a2f846160633d4bf4b6ec83;p=osmocom-bb.git diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c index 0e4c2de..e2418cc 100644 --- a/src/host/layer23/src/mobile/gsm48_rr.c +++ b/src/host/layer23/src/mobile/gsm48_rr.c @@ -1,4 +1,3 @@ -#warning rr on MDL error handling (as specified in 04.08 / 04.06) /* * (C) 2010 by Andreas Eversberg * @@ -41,6 +40,25 @@ * */ +/* Testing delayed (immediate) assigment / handover + * + * When enabled, the starting time will be set by given frames in the future. + * If a starting time is given by the network, this time is ignored. + */ +//#define TEST_STARTING_TIMER 140 + +/* Testing if frequency modification works correctly "after time". + * + * When enabled, the starting time will be set in the future. + * A wrong channel is defined "before time", so noise is received until + * starting time elapses. + * If a starting time is given by the network, this time is ignored. + * Also channel definitions "before time" are ignored. + * + * NOTE: TEST_STARTING_TIMER MUST be defined also. + */ +//#define TEST_FREQUENCY_MOD + #include #include #include @@ -63,6 +81,8 @@ static void start_rr_t_monitor(struct gsm48_rrlayer *rr, int sec, int micro); static void stop_rr_t_monitor(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_dl_est(struct osmocom_ms *ms); @@ -86,6 +106,17 @@ int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc, return 0; } +int gsm48_encode_lai(struct gsm48_loc_area_id *lai, uint16_t mcc, + uint16_t mnc, uint16_t lac) +{ + lai->digits[0] = (mcc >> 8) | (mcc & 0xf0); + lai->digits[1] = (mcc & 0x0f) | (mnc << 4); + lai->digits[2] = (mnc >> 8) | (mnc & 0xf0); + lai->lac = htons(lac); + + return 0; +} + static int gsm48_decode_chan_h0(struct gsm48_chan_desc *cd, uint8_t *tsc, uint16_t *arfcn) { @@ -181,6 +212,28 @@ static int gsm48_decode_ba_range(const uint8_t *ba, uint8_t ba_len, return 0; } +/* decode "Cell Description" (10.5.2.2) */ +static int gsm48_decode_cell_desc(struct gsm48_cell_desc *cd, uint16_t *arfcn, + uint8_t *ncc, uint8_t *bcc) +{ + *arfcn = (cd->arfcn_hi << 8) + cd->arfcn_lo; + *ncc = cd->ncc; + *bcc = cd->bcc; + + return 0; +} + +/* decode "Synchronization Indication" (10.5.2.39) */ +static int gsm48_decode_sync_ind(struct gsm48_rrlayer *rr, + struct gsm48_sync_ind *si) +{ + rr->hando_sync_ind = si->si; + rr->hando_rot = si->rot; + rr->hando_nci = si->nci; + + return 0; +} + /* 3.1.4.3 set sequence number and increment */ static int gsm48_apply_v_sd(struct gsm48_rrlayer *rr, struct msgb *msg) { @@ -252,9 +305,13 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state) gsm48_rr_state_names[rr->state], gsm48_rr_state_names[state]); /* abort handover, in case of release of dedicated mode */ - if (rr->state == GSM48_RR_ST_DEDICATED && state != rr->state) { - rr->hando_susp_state = 0; - rr->assign_susp_state = 0; + if (rr->state == GSM48_RR_ST_DEDICATED) { + /* disable handover / assign state */ + rr->modify_state = GSM48_RR_MOD_NONE; + /* stop start_time_timer */ + stop_rr_t_starting(rr); + /* stop handover timer */ + stop_rr_t3124(rr); } rr->state = state; @@ -277,7 +334,7 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state) msgb_free(msg); /* clear all descriptions of last channel */ memset(&rr->cd_now, 0, sizeof(rr->cd_now)); - /* reset cipering */ + /* reset ciphering */ rr->cipher_on = 0; /* tell cell selection process to return to idle mode * NOTE: this must be sent unbuffered, because it will @@ -476,7 +533,7 @@ static void timeout_rr_monitor(void *arg) rxlev = meas->rxlev / meas->frames; berr = meas->berr / meas->frames; snr = meas->snr / meas->frames; - sprintf(text, "MON: arfcn=%d lev=%s snr=%2d ber=%2d " + sprintf(text, "MON: f=%d lev=%s snr=%2d ber=%3d " "LAI=%s %s %04x ID=%04x", cs->sel_arfcn, gsm_print_rxlev(rxlev), berr, snr, gsm_print_mcc(cs->sel_mcc), @@ -499,6 +556,29 @@ static void timeout_rr_monitor(void *arg) start_rr_t_monitor(rr, 1, 0); } +/* special timer to assign / handover when starting time is reached */ +static void timeout_rr_t_starting(void *arg) +{ + struct gsm48_rrlayer *rr = arg; + struct msgb *nmsg; + + LOGP(DRR, LOGL_INFO, "starting timer has fired\n"); + + /* open channel when starting timer of IMM.ASS has fired */ + if (rr->modify_state == GSM48_RR_MOD_IMM_ASS) { + rr->modify_state = GSM48_RR_MOD_NONE; + gsm48_rr_dl_est(rr->ms); + return; + } + + /* start suspension of current link */ + LOGP(DRR, LOGL_INFO, "request suspension of data link\n"); + nmsg = gsm48_l3_msgb_alloc(); + if (!nmsg) + return; + gsm48_send_rsl(rr->ms, RSL_MT_SUSP_REQ, nmsg); +} + /* special timer to ensure that UA is sent before disconnecting channel */ static void timeout_rr_t_rel_wait(void *arg) { @@ -539,6 +619,11 @@ static void timeout_rr_t3122(void *arg) LOGP(DRR, LOGL_INFO, "timer T3122 has fired\n"); } +static void timeout_rr_t3124(void *arg) +{ + LOGP(DRR, LOGL_INFO, "timer T3124 has fired\n"); +} + static void timeout_rr_t3126(void *arg) { struct gsm48_rrlayer *rr = arg; @@ -569,15 +654,26 @@ static void start_rr_t_monitor(struct gsm48_rrlayer *rr, int sec, int micro) static void start_rr_t_rel_wait(struct gsm48_rrlayer *rr, int sec, int micro) { - LOGP(DRR, LOGL_INFO, "starting T_rel_wait with %d seconds\n", sec); + LOGP(DRR, LOGL_INFO, "starting T_rel_wait with %d.%03d seconds\n", sec, + micro / 1000); rr->t_rel_wait.cb = timeout_rr_t_rel_wait; rr->t_rel_wait.data = rr; bsc_schedule_timer(&rr->t_rel_wait, sec, micro); } +static void start_rr_t_starting(struct gsm48_rrlayer *rr, int sec, int micro) +{ + LOGP(DRR, LOGL_INFO, "starting T_starting with %d.%03d seconds\n", sec, + micro / 1000); + rr->t_starting.cb = timeout_rr_t_starting; + rr->t_starting.data = rr; + bsc_schedule_timer(&rr->t_starting, sec, micro); +} + static void start_rr_t3110(struct gsm48_rrlayer *rr, int sec, int micro) { - LOGP(DRR, LOGL_INFO, "starting T3110 with %d seconds\n", sec); + LOGP(DRR, LOGL_INFO, "starting T3110 with %d.%03d seconds\n", sec, + micro / 1000); rr->t3110.cb = timeout_rr_t3110; rr->t3110.data = rr; bsc_schedule_timer(&rr->t3110, sec, micro); @@ -585,15 +681,26 @@ static void start_rr_t3110(struct gsm48_rrlayer *rr, int sec, int micro) static void start_rr_t3122(struct gsm48_rrlayer *rr, int sec, int micro) { - LOGP(DRR, LOGL_INFO, "starting T3122 with %d seconds\n", sec); + LOGP(DRR, LOGL_INFO, "starting T3122 with %d.%03d seconds\n", sec, + micro / 1000); rr->t3122.cb = timeout_rr_t3122; rr->t3122.data = rr; bsc_schedule_timer(&rr->t3122, sec, micro); } +static void start_rr_t3124(struct gsm48_rrlayer *rr, int sec, int micro) +{ + LOGP(DRR, LOGL_INFO, "starting T3124 with %d.%03d seconds\n", sec, + micro / 1000); + rr->t3124.cb = timeout_rr_t3124; + rr->t3124.data = rr; + bsc_schedule_timer(&rr->t3124, sec, micro); +} + static void start_rr_t3126(struct gsm48_rrlayer *rr, int sec, int micro) { - LOGP(DRR, LOGL_INFO, "starting T3126 with %d seconds\n", sec); + LOGP(DRR, LOGL_INFO, "starting T3126 with %d.%03d seconds\n", sec, + micro / 1000); rr->t3126.cb = timeout_rr_t3126; rr->t3126.data = rr; bsc_schedule_timer(&rr->t3126, sec, micro); @@ -607,6 +714,14 @@ static void stop_rr_t_monitor(struct gsm48_rrlayer *rr) } } +static void stop_rr_t_starting(struct gsm48_rrlayer *rr) +{ + if (bsc_timer_pending(&rr->t_starting)) { + LOGP(DRR, LOGL_INFO, "stopping pending timer T_starting\n"); + bsc_del_timer(&rr->t_starting); + } +} + static void stop_rr_t_rel_wait(struct gsm48_rrlayer *rr) { if (bsc_timer_pending(&rr->t_rel_wait)) { @@ -631,6 +746,14 @@ static void stop_rr_t3122(struct gsm48_rrlayer *rr) } } +static void stop_rr_t3124(struct gsm48_rrlayer *rr) +{ + if (bsc_timer_pending(&rr->t3124)) { + LOGP(DRR, LOGL_INFO, "stopping pending timer T3124\n"); + bsc_del_timer(&rr->t3124); + } +} + static void stop_rr_t3126(struct gsm48_rrlayer *rr) { if (bsc_timer_pending(&rr->t3126)) { @@ -677,6 +800,7 @@ static int gsm48_rr_tx_cip_mode_cpl(struct osmocom_ms *ms, uint8_t cr) struct gsm_settings *set = &ms->settings; struct msgb *nmsg; struct gsm48_hdr *gh; + struct gsm48_rr_hdr *nrrh; uint8_t buf[11], *tlv; LOGP(DRR, LOGL_INFO, "CIPHERING MODE COMPLETE (cr %d)\n", cr); @@ -692,17 +816,28 @@ static int gsm48_rr_tx_cip_mode_cpl(struct osmocom_ms *ms, uint8_t cr) /* MI */ if (cr) { gsm48_generate_mid_from_imsi(buf, set->imeisv); + /* alter MI type */ + buf[2] = (buf[2] & ~GSM_MI_TYPE_MASK) | GSM_MI_TYPE_IMEISV; tlv = msgb_put(nmsg, 2 + buf[1]); memcpy(tlv, buf, 2 + buf[1]); } - return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg); + gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg); + + /* send RR_SYNC_IND(ciphering) */ + nmsg = gsm48_rr_msgb_alloc(GSM48_RR_SYNC_IND); + if (!nmsg) + return -ENOMEM; + nrrh = (struct gsm48_rr_hdr *)nmsg->data; + nrrh->cause = RR_SYNC_CAUSE_CIPHERING; + return gsm48_rr_upmsg(ms, nmsg); } /* receive ciphering mode command */ static int gsm48_rr_rx_cip_mode_cmd(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_rrlayer *rr = &ms->rrlayer; + struct gsm_subscriber *subscr = &ms->subscr; struct gsm_support *sup = &ms->support; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_cip_mode_cmd *cm = (struct gsm48_cip_mode_cmd *)gh->data; @@ -722,38 +857,48 @@ static int gsm48_rr_rx_cip_mode_cmd(struct osmocom_ms *ms, struct msgb *msg) /* cipher mode response */ cr = cm->cr; - if (sc) - LOGP(DRR, LOGL_INFO, "CIPHERING MODE COMMAND (sc=%u, cr=%u)", + if (!sc) + LOGP(DRR, LOGL_INFO, "CIPHERING MODE COMMAND (sc=%u, cr=%u)\n", sc, cr); else LOGP(DRR, LOGL_INFO, "CIPHERING MODE COMMAND (sc=%u, " - "algo=A5/%d cr=%u)", sc, alg_id + 1, cr); + "algo=A5/%d cr=%u)\n", sc, alg_id + 1, cr); /* 3.4.7.2 */ if (rr->cipher_on && sc) { - LOGP(DRR, LOGL_INFO, "cipering already applied.\n"); + LOGP(DRR, LOGL_NOTICE, "chiphering already applied\n"); return gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC); } /* check if we actually support this cipher */ - if ((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 && !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))) { + LOGP(DRR, LOGL_NOTICE, "algo not supported\n"); return gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_CHAN_MODE_UNACCT); + } + + /* check if we have no key */ + if (sc && subscr->key_seq == 7) { + LOGP(DRR, LOGL_NOTICE, "no key available\n"); + return gsm48_rr_tx_rr_status(ms, + GSM48_RR_CAUSE_PROT_ERROR_UNSPC); + } /* change to ciphering */ -#ifdef TODO - rsl command to activate ciperhing -#endif rr->cipher_on = sc, rr->cipher_type = alg_id; + if (sc) + l1ctl_tx_crypto_req(ms, alg_id + 1, subscr->key, 8); + else + l1ctl_tx_crypto_req(ms, 0, NULL, 0); - /* response */ + /* response (using the new mode) */ return gsm48_rr_tx_cip_mode_cpl(ms, cr); } @@ -884,7 +1029,7 @@ int gsm48_rr_enc_cm2(struct osmocom_ms *ms, struct gsm48_classmark2 *cm) cm->pwr_lev = sup->pwr_lev_1800; else cm->pwr_lev = sup->pwr_lev_900; - cm->a5_1 = sup->a5_1; + cm->a5_1 = !sup->a5_1; cm->es_ind = sup->es_ind; cm->rev_lev = sup->rev_lev; cm->fc = (sup->r_gsm || sup->e_gsm); @@ -2046,6 +2191,7 @@ static int gsm48_rr_chan2cause[4] = { /* given LV of mobile identity is checked agains ms */ static int gsm_match_mi(struct osmocom_ms *ms, uint8_t *mi) { + struct gsm322_cellsel *cs = &ms->cellsel; char imsi[16]; uint32_t tmsi; uint8_t mi_type; @@ -2059,7 +2205,9 @@ static int gsm_match_mi(struct osmocom_ms *ms, uint8_t *mi) return 0; memcpy(&tmsi, mi+2, 4); if (ms->subscr.tmsi == ntohl(tmsi) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(tmsi)); @@ -2174,7 +2322,9 @@ static int gsm48_rr_rx_pag_req_2(struct osmocom_ms *ms, struct msgb *msg) chan_2 = pa->cneed2; /* first MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi1) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi1)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1); } else @@ -2182,7 +2332,9 @@ static int gsm48_rr_rx_pag_req_2(struct osmocom_ms *ms, struct msgb *msg) ntohl(pa->tmsi1)); /* second MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi2) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi2)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1); } else @@ -2236,7 +2388,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg) chan_4 = pa->cneed4; /* first MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi1) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi1)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1); } else @@ -2244,7 +2398,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg) ntohl(pa->tmsi1)); /* second MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi2) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi2)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1); } else @@ -2252,7 +2408,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg) ntohl(pa->tmsi2)); /* thrid MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi3) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi3)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1); } else @@ -2260,7 +2418,9 @@ static int gsm48_rr_rx_pag_req_3(struct osmocom_ms *ms, struct msgb *msg) ntohl(pa->tmsi3)); /* fourth MI */ if (ms->subscr.tmsi == ntohl(pa->tmsi4) - && ms->subscr.tmsi_valid) { + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi4)); return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_4], 1); } else @@ -2318,7 +2478,9 @@ static int gsm48_rr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg) int ma_len = msgb_l3len(msg) - sizeof(*ia); uint8_t ch_type, ch_subch, ch_ts; struct gsm48_rr_cd cd; +#ifndef TEST_STARTING_TIMER uint8_t *st, st_len; +#endif memset(&cd, 0, sizeof(cd)); @@ -2335,10 +2497,16 @@ static int gsm48_rr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg) } /* starting time */ +#ifdef TEST_STARTING_TIMER + cd.start = 1; + cd.start_tm.fn = (ms->meas.last_fn + TEST_STARTING_TIMER) % 42432; + LOGP(DRR, LOGL_INFO, " TESTING: starting time ahead\n"); +#else st_len = ma_len - ia->mob_alloc_len; st = ia->mob_alloc + ia->mob_alloc_len; if (st_len >= 3 && st[0] == GSM48_IE_START_TIME) gsm48_decode_start_time(&cd, (struct gsm48_start_time *)(st+1)); +#endif /* decode channel description */ LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT:\n"); @@ -2386,6 +2554,10 @@ static int gsm48_rr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg) memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len, ia->mob_alloc_len + 1); rr->wait_assign = 2; + /* reset scheduler */ + LOGP(DRR, LOGL_INFO, "resetting scheduler\n"); + l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED); + return gsm48_rr_dl_est(ms); } LOGP(DRR, LOGL_INFO, "Request, but not for us.\n"); @@ -2401,7 +2573,9 @@ static int gsm48_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg) int ma_len = msgb_l3len(msg) - sizeof(*ia); uint8_t ch_type, ch_subch, ch_ts; struct gsm48_rr_cd cd1, cd2; +#ifndef TEST_STARTING_TIMER uint8_t *st, st_len; +#endif memset(&cd1, 0, sizeof(cd1)); memset(&cd2, 0, sizeof(cd2)); @@ -2418,6 +2592,12 @@ static int gsm48_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg) return -EINVAL; } +#ifdef TEST_STARTING_TIMER + cd1.start = 1; + cd2.start_tm.fn = (ms->meas.last_fn + TEST_STARTING_TIMER) % 42432; + memcpy(&cd2, &cd1, sizeof(cd2)); + LOGP(DRR, LOGL_INFO, " TESTING: starting time ahead\n"); +#else /* starting time */ st_len = ma_len - ia->mob_alloc_len; st = ia->mob_alloc + ia->mob_alloc_len; @@ -2426,6 +2606,7 @@ static int gsm48_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg) (struct gsm48_start_time *)(st+1)); memcpy(&cd2, &cd1, sizeof(cd2)); } +#endif /* decode channel description */ LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT EXTENDED:\n"); @@ -2495,6 +2676,10 @@ static int gsm48_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg) memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len, ia->mob_alloc_len + 1); rr->wait_assign = 2; + /* reset scheduler */ + LOGP(DRR, LOGL_INFO, "resetting scheduler\n"); + l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED); + return gsm48_rr_dl_est(ms); } /* request ref 1 */ @@ -2507,6 +2692,10 @@ static int gsm48_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg) memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len, ia->mob_alloc_len + 1); rr->wait_assign = 2; + /* reset scheduler */ + LOGP(DRR, LOGL_INFO, "resetting scheduler\n"); + l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED); + return gsm48_rr_dl_est(ms); } LOGP(DRR, LOGL_INFO, "Request, but not for us.\n"); @@ -2564,7 +2753,7 @@ static int gsm48_rr_rx_imm_ass_rej(struct osmocom_ms *ms, struct msgb *msg) return 0; } -/* 9.1.1 ADDITIONAL ASSIGMENT is received */ +/* 9.1.1 ADDITIONAL ASSIGMENT is received */ static int gsm48_rr_rx_add_ass(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); @@ -2727,10 +2916,6 @@ static int gsm48_rr_activate_channel(struct osmocom_ms *ms, struct gsm_settings *set = &ms->settings; uint8_t ch_type, ch_subch, ch_ts; - /* reset scheduler */ - LOGP(DRR, LOGL_INFO, "resetting scheduler\n"); - l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED); - /* setting (new) timing advance */ LOGP(DRR, LOGL_INFO, "setting indicated TA %d (actual TA %d)\n", cd->ind_ta, cd->ind_ta - set->alter_delay); @@ -2759,6 +2944,21 @@ static int gsm48_rr_activate_channel(struct osmocom_ms *ms, return 0; } +/* frequency change of channel "after time" */ +static int gsm48_rr_channel_after_time(struct osmocom_ms *ms, + struct gsm48_rr_cd *cd, uint16_t *ma, uint8_t ma_len, uint16_t fn) +{ + if (cd->h) + l1ctl_tx_dm_freq_req_h1(ms, cd->maio, cd->hsn, + ma, ma_len, cd->tsc, fn); + else + l1ctl_tx_dm_freq_req_h0(ms, cd->arfcn, cd->tsc, fn); + +#warning FIXME: channel mode, cyphering command + + return 0; +} + /* render list of hopping channels from channel description elements */ static int gsm48_rr_render_ma(struct osmocom_ms *ms, struct gsm48_rr_cd *cd, uint16_t *ma, uint8_t *ma_len) @@ -2795,8 +2995,9 @@ static int gsm48_rr_render_ma(struct osmocom_ms *ms, struct gsm48_rr_cd *cd, cd->mob_alloc_lv[0], ma, ma_len, 0); if (*ma_len < 1) { LOGP(DRR, LOGL_NOTICE, "mobile allocation with no " - "frequency\n"); - return GSM48_RR_CAUSE_ABNORMAL_UNSPEC; + "frequency available\n"); + return GSM48_RR_CAUSE_NO_CELL_ALLOC_A; + } } else /* decode frequency list */ @@ -2875,13 +3076,6 @@ static int gsm48_rr_render_ma(struct osmocom_ms *ms, struct gsm48_rr_cd *cd, } } -#if 0 - if (no CA) { - LOGP(DRR, LOGL_NOTICE, "No current cell allocation available.\n"); - return GSM48_GSM48_RR_CAUSE_NO_CELL_ALLOC_A; - } -#endif - return 0; } @@ -2889,6 +3083,7 @@ static int gsm48_rr_render_ma(struct osmocom_ms *ms, struct gsm48_rr_cd *cd, static int gsm48_rr_dl_est(struct osmocom_ms *ms) { struct gsm48_rrlayer *rr = &ms->rrlayer; + struct gsm322_cellsel *cs = &ms->cellsel; struct gsm_subscriber *subscr = &ms->subscr; struct msgb *nmsg; struct gsm48_hdr *gh; @@ -2897,6 +3092,41 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms) uint16_t ma[64]; uint8_t ma_len; + /* check if we have to change channel at starting time (we delay) */ + if (rr->cd_now.start) { + int32_t now, start, diff; + uint32_t start_mili = 0; + + /* how much time do we have left? */ + now = ms->meas.last_fn % 42432; + start = rr->cd_now.start_tm.fn % 42432; + diff = start - now; + if (diff < 0) + diff += 42432; + LOGP(DRR, LOGL_INFO, " (Tnow %d Tstart %d diff %d)\n", + now, start, diff); + start_mili = (uint32_t)diff * 19580 / 42432 * 10; + if (diff >= 32024 || !start_mili) { + LOGP(DRR, LOGL_INFO, " -> Start time already " + "elapsed\n"); + rr->cd_now.start = 0; + } else { + LOGP(DRR, LOGL_INFO, " -> Start time is %d ms in the " + "future\n", start_mili); + } + +#ifndef TEST_FREQUENCY_MOD + /* schedule start of IMM.ASS */ + rr->modify_state = GSM48_RR_MOD_IMM_ASS; + start_rr_t_starting(rr, start_mili / 1000, + (start_mili % 1000) * 1000); + /* when timer fires, start time is already elapsed */ + rr->cd_now.start = 0; + + return 0; +#endif + } + /* get hopping sequence, if required */ if (gsm48_rr_render_ma(ms, &rr->cd_now, ma, &ma_len)) return -EINVAL; @@ -2932,7 +3162,10 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms) pr->cm2_len = sizeof(pr->cm2); gsm48_rr_enc_cm2(ms, &pr->cm2); /* mobile identity */ - if (ms->subscr.tmsi_valid) { + if (ms->subscr.tmsi != 0xffffffff + && ms->subscr.mcc == cs->sel_mcc + && ms->subscr.mnc == cs->sel_mnc + && ms->subscr.lac == cs->sel_lac) { gsm48_generate_mid_from_tmsi(mi, subscr->tmsi); LOGP(DRR, LOGL_INFO, "sending paging response with " "TMSI\n"); @@ -2950,8 +3183,22 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms) memcpy(pr->data, mi + 1, 1 + mi[1]); } +#ifdef TEST_FREQUENCY_MOD + LOGP(DRR, LOGL_INFO, " TESTING: frequency modify IMM.ASS\n"); + memcpy(&rr->cd_before, &rr->cd_now, sizeof(rr->cd_before)); + rr->cd_before.h = 0; + rr->cd_before.arfcn = 0; + /* activate channel */ + gsm48_rr_activate_channel(ms, &rr->cd_before, ma, ma_len); + /* render channel "after time" */ + gsm48_rr_render_ma(ms, &rr->cd_now, ma, &ma_len); + /* schedule change of channel */ + gsm48_rr_channel_after_time(ms, &rr->cd_now, ma, ma_len, + rr->cd_now.start_tm.fn); +#else /* activate channel */ gsm48_rr_activate_channel(ms, &rr->cd_now, ma, ma_len); +#endif /* start establishmnet */ return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg); @@ -3064,9 +3311,91 @@ static int gsm48_rr_rx_chan_rel(struct osmocom_ms *ms, struct msgb *msg) } /* - * chanel mode modify, assignment, and handover + * frequency redefition, chanel mode modify, assignment, and handover */ +/* 9.1.13 FREQUENCY REDEFINITION is received */ +static int gsm48_rr_rx_frq_redef(struct osmocom_ms *ms, struct msgb *msg) +{ +#warning disabled, until added to libosmocore +#if 0 + struct gsm48_rrlayer *rr = &ms->rrlayer; + struct gsm48_frq_redef *fr = msgb_l3(msg); + int mob_al_len = msgb_l3len(msg) - sizeof(*fr); + uint8_t ch_type, ch_subch, ch_ts; + struct gsm48_rr_cd cd; + uint8_t cause; + uint8_t *st; + uint16_t ma[64]; + uint8_t ma_len; + + memcpy(&cd, &rr->cd_now, sizeof(cd)); + + if (mob_al_len < 0 /* mobile allocation IE must be included */ + || fr->mob_alloc_len + 2 > mob_al_len) { /* short read of IE */ + LOGP(DRR, LOGL_NOTICE, "Short read of FREQUENCY REDEFINITION " + "message.\n"); + return -EINVAL; + } + if (fr->mob_alloc_len > 8) { + LOGP(DRR, LOGL_NOTICE, "Moble allocation in FREQUENCY " + "REDEFINITION too large.\n"); + return -EINVAL; + } + + /* decode channel description */ + LOGP(DRR, LOGL_INFO, "FREQUENCY REDEFINITION:\n"); + cd.chan_nr = fr->chan_desc.chan_nr; + rsl_dec_chan_nr(cd.chan_nr, &ch_type, &ch_subch, &ch_ts); + if (fr->chan_desc.h0.h) { + cd.h = 1; + gsm48_decode_chan_h1(&fr->chan_desc, &cd.tsc, &cd.maio, + &cd.hsn); + LOGP(DRR, LOGL_INFO, " (MAIO %u HSN %u TS %u SS %u TSC %u)\n", + cd.maio, cd.hsn, ch_ts, ch_subch, cd.tsc); + } else { + cd.h = 0; + gsm48_decode_chan_h0(&fr->chan_desc, &cd.tsc, &cd.arfcn); + LOGP(DRR, LOGL_INFO, " (ARFCN %u TS %u SS %u TSC %u)\n", + cd.arfcn, ch_ts, ch_subch, cd.tsc); + } + + /* mobile allocation */ + memcpy(&rr->cd_now.mob_alloc_lv, &fr->mob_alloc_len, + fr->mob_alloc_len + 1); + + /* starting time */ + st = fr->mob_alloc + fr->mob_alloc_len; + gsm48_decode_start_time(&cd, (struct gsm48_start_time *)(st+1)); + + /* cell channel description */ + if (mob_al_len >= fr->mob_alloc_len + 2 + 17 + && fr->mob_alloc[fr->mob_alloc_len + 2] == GSM48_IE_CELL_CH_DESC) { + const uint8_t *v = fr->mob_alloc + fr->mob_alloc_len + 3 + 1; + + LOGP(DRR, LOGL_INFO, " using cell channel description)\n"); + memcpy(&cd.cell_desc_lv + 1, v, 17); + cd.cell_desc_lv[0] = 16; + } + + /* render channel "after time" */ + cause = gsm48_rr_render_ma(ms, &rr->cd_now, ma, &ma_len); + if (cause) + return gsm48_rr_tx_rr_status(ms, cause); + + /* update to new channel data */ + memcpy(&rr->cd_now, &cd, sizeof(rr->cd_now)); + + /* schedule change of channel */ + gsm48_rr_channel_after_time(ms, &rr->cd_now, ma, ma_len, + rr->cd_now.start_tm.fn); + + rr->cd_now.start = 0; + +#endif + return 0; +} + /* 9.1.6 sending CHANNEL MODE MODIFY ACKNOWLEDGE */ static int gsm48_rr_tx_chan_modify_ack(struct osmocom_ms *ms, struct gsm48_chan_desc *cd, uint8_t mode) @@ -3146,7 +3475,7 @@ static int gsm48_rr_rx_chan_modify(struct osmocom_ms *ms, struct msgb *msg) LOGP(DRR, LOGL_ERROR, "Mode %u not supported!\n", mode); } rr->cd_now.mode = mode; -#warning FIXME: set mode +#warning FIXME: channel mode return gsm48_rr_tx_chan_modify_ack(ms, &cm->chan_desc, mode); } @@ -3273,20 +3602,18 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg) } /* starting time */ +#ifdef TEST_STARTING_TIMER + cda->start = 1; + cda->start_tm.fn = (ms->meas.last_fn + TEST_STARTING_TIMER) % 42432; + LOGP(DRR, LOGL_INFO, " TESTING: starting time ahead\n"); +#else if (TLVP_PRESENT(&tp, GSM48_IE_START_TIME)) { gsm48_decode_start_time(cda, (struct gsm48_start_time *) TLVP_VAL(&tp, GSM48_IE_START_TIME)); /* 9.1.2.5 "... before time IE is not present..." */ if (!before_time) { LOGP(DRR, LOGL_INFO, " -> channel description after " - "time only, using it before time also\n"); - before_time = 1; - cdb->tsc = cda->tsc; - cdb->h = cda->h; - cdb->arfcn = cda->arfcn; - cdb->maio = cda->maio; - cdb->hsn = cda->hsn; - cdb->chan_nr = cda->chan_nr; + "time only, but starting time\n"); } else LOGP(DRR, LOGL_INFO, " -> channel description before " "and after time\n"); @@ -3298,6 +3625,7 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg) "time, but no starting time, ignoring!\n"); } } +#endif /* mobile allocation / frequency list after time */ if (cda->h) { @@ -3432,30 +3760,27 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg) LOGP(DRR, LOGL_INFO, " both: (tx_power %d TA %d)\n", cda->ind_tx_power, cda->ind_ta); - /* check if we have to change channel "before time" */ - if (before_time) { - uint16_t now, start, diff; + /* check if we have to change channel at starting time */ + if (cda->start) { + int32_t now, start, diff; /* how much time do we have left? */ now = ms->meas.last_fn % 42432; start = cda->start_tm.fn % 42432; - diff = (start - now) % 42432; - LOGP(DRR, LOGL_INFO, " after: (Tnow %d Tstart %d)\n", now, - start); - if (diff >= 32024) { - LOGP(DRR, LOGL_INFO, " -> Start time is in the past\n"); + diff = start - now; + if (diff < 0) + diff += 42432; + LOGP(DRR, LOGL_INFO, " after: (Tnow %d Tstart %d diff %d)\n", + now, start, diff); + start_mili = (uint32_t)diff * 19580 / 42432 * 10; + if (diff >= 32024 || !start_mili) { + LOGP(DRR, LOGL_INFO, " -> Start time already " + "elapsed\n"); before_time = 0; + cda->start = 0; } else { - start_mili = (uint32_t)diff * 19580 / 42432 * 10; LOGP(DRR, LOGL_INFO, " -> Start time is %d ms in the " "future\n", start_mili); - /* GSM 05.10 Clause 6.8 */ - if (start_mili < 120) { - LOGP(DRR, LOGL_INFO, " -> Start time too close " - "in the future, ignoring channel " - "before time\n"); - before_time = 0; - } } } @@ -3477,121 +3802,531 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg) } #endif +#ifdef TEST_FREQUENCY_MOD + LOGP(DRR, LOGL_INFO, " TESTING: frequency modify ASS.CMD\n"); + before_time = 1; + memcpy(cdb, cda, sizeof(*cdb)); + cdb->h = 0; + cdb->arfcn = 0; +#endif + /* schedule start of assignment */ - if (before_time) { - LOGP(DRR, LOGL_INFO, "FIXME starting time not supported yet\n"); - return -ENOTSUP; + rr->modify_state = GSM48_RR_MOD_ASSIGN; + if (!before_time && cda->start) { + start_rr_t_starting(rr, start_mili / 1000, start_mili % 1000); + /* when timer fires, start time is already elapsed */ + cda->start = 0; + + return 0; } - /* start suspension of current link */ + /* if no starting time, start suspension of current link directly */ LOGP(DRR, LOGL_INFO, "request suspension of data link\n"); nmsg = gsm48_l3_msgb_alloc(); if (!nmsg) return -ENOMEM; gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg); - /* change into special assignment suspension state */ - rr->assign_susp_state = 1; - rr->resume_last_state = 0; - return 0; } -/* send all queued messages down to layer 2 */ -static int gsm48_rr_dequeue_down(struct osmocom_ms *ms) +/* 9.1.16 sending HANDOVER COMPLETE */ +static int gsm48_rr_tx_hando_cpl(struct osmocom_ms *ms, uint8_t cause) { - struct gsm48_rrlayer *rr = &ms->rrlayer; - struct msgb *msg; +#warning disabled, until added to libosmocore +#if 0 + struct msgb *nmsg; + struct gsm48_hdr *gh; + struct gsm48_ho_cpl *hc; - while((msg = msgb_dequeue(&rr->downqueue))) { - LOGP(DRR, LOGL_INFO, "Sending queued message.\n"); - gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg); - } + LOGP(DRR, LOGL_INFO, "HANDOVER COMPLETE (cause #%d)\n", cause); - return 0; -} + nmsg = gsm48_l3_msgb_alloc(); + if (!nmsg) + return -ENOMEM; + gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh)); + hc = (struct gsm48_ho_cpl *) msgb_put(nmsg, sizeof(*hc)); -/* channel is resumed in dedicated mode */ -static int gsm48_rr_estab_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg) -{ - struct gsm48_rrlayer *rr = &ms->rrlayer; + gh->proto_discr = GSM48_PDISC_RR; + gh->msg_type = GSM48_MT_RR_HANDO_COMPL; - if (rr->hando_susp_state || rr->assign_susp_state) { - LOGP(DRR, LOGL_INFO, "data link is resumed\n"); + /* RR_CAUSE */ + hc->rr_cause = cause; - if (rr->resume_last_state) { - rr->resume_last_state = 0; - gsm48_rr_tx_ass_fail(ms, - GSM48_RR_CAUSE_PROT_ERROR_UNSPC); - } else { - gsm48_rr_tx_ass_cpl(ms, GSM48_RR_CAUSE_NORMAL); - } - /* transmit queued frames during ho / ass transition */ - gsm48_rr_dequeue_down(ms); - } + // FIXME: mobile observed time - return 0; + return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg); +#endif } -/* suspend confirm in dedicated mode */ -static int gsm48_rr_susp_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg) +/* 9.1.4 sending HANDOVER FAILURE */ +static int gsm48_rr_tx_hando_fail(struct osmocom_ms *ms, uint8_t cause) { - struct gsm48_rrlayer *rr = &ms->rrlayer; - - if (rr->hando_susp_state || rr->assign_susp_state) { - struct msgb *nmsg; - uint16_t ma[64]; - uint8_t ma_len; - - LOGP(DRR, LOGL_INFO, "suspend complete, request resume of " - "data link\n"); +#warning disabled, until added to libosmocore +#if 0 + struct msgb *nmsg; + struct gsm48_hdr *gh; + struct gsm48_ho_fail *hf; - /* deactivating dedicated mode */ - LOGP(DRR, LOGL_INFO, "leaving dedicated mode\n"); - l1ctl_tx_dm_rel_req(rr->ms); + LOGP(DRR, LOGL_INFO, "HANDOVER FAILURE (cause #%d)\n", cause); - /* store current channel descriptions */ - memcpy(&rr->cd_last, &rr->cd_now, sizeof(rr->cd_last)); - /* copy channel description "after time" */ - memcpy(&rr->cd_now, &rr->cd_after, sizeof(rr->cd_now)); + nmsg = gsm48_l3_msgb_alloc(); + if (!nmsg) + return -ENOMEM; + gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh)); + hf = (struct gsm48_ho_fail *) msgb_put(nmsg, sizeof(*hf)); - /* render and activate channel */ - gsm48_rr_render_ma(ms, &rr->cd_now, ma, &ma_len); - gsm48_rr_activate_channel(ms, &rr->cd_now, ma, ma_len); + gh->proto_discr = GSM48_PDISC_RR; + gh->msg_type = GSM48_MT_RR_ASS_COMPL; - /* 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); + /* RR_CAUSE */ + hf->rr_cause = cause; -#ifdef TODO - /* trigger RACH */ - if (rr->hando_susp_state) { - gsm48_rr_tx_hando_access(ms); - rr->hando_acc_left = 3; - } + return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg); #endif - } - return 0; } -/* - * radio ressource requests - */ - -/* establish request for dedicated mode */ -static int gsm48_rr_est_req(struct osmocom_ms *ms, struct msgb *msg) +/* receiving HANDOVER COMMAND message (9.1.15) */ +static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_rrlayer *rr = &ms->rrlayer; - struct gsm322_cellsel *cs = &ms->cellsel; - struct gsm48_sysinfo *s = cs->si; - struct gsm_subscriber *subscr = &ms->subscr; - struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data; struct gsm48_hdr *gh = msgb_l3(msg); - uint8_t cause; - struct msgb *nmsg; + struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *)gh->data; + int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*ho); + struct tlv_parsed tp; + struct gsm48_rr_cd *cda = &rr->cd_after; + struct gsm48_rr_cd *cdb = &rr->cd_before; + uint16_t arfcn; + uint8_t bcc, ncc; + uint8_t ch_type, ch_subch, ch_ts; + uint8_t before_time = 0; + uint16_t ma[64]; + uint8_t ma_len; + uint32_t start_mili = 0; + uint8_t cause; + struct msgb *nmsg; + + LOGP(DRR, LOGL_INFO, "HANDOVER COMMAND\n"); + + memset(cda, 0, sizeof(*cda)); + memset(cdb, 0, sizeof(*cdb)); + + if (payload_len < 0) { + LOGP(DRR, LOGL_NOTICE, "Short read of HANDOVER COMMAND " + "message.\n"); + return gsm48_rr_tx_rr_status(ms, + GSM48_RR_CAUSE_PROT_ERROR_UNSPC); + } + + /* cell description */ + gsm48_decode_cell_desc(&ho->cell_desc, &arfcn, &ncc, &bcc); + + /* handover reference */ + rr->chan_req_val = ho->ho_ref; + rr->chan_req_mask = 0x00; + + /* sync ind */ + if (TLVP_PRESENT(&tp, GSM48_IE_SYNC_IND)) { + gsm48_decode_sync_ind(rr, (struct gsm48_sync_ind *) + TLVP_VAL(&tp, GSM48_IE_SYNC_IND)); + LOGP(DRR, LOGL_INFO, " (sync_ind=%d rot=%d nci=%d)\n", + 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 *) + TLVP_VAL(&tp, GSM48_IE_CH_DESC_1_BEFORE); + cdb->chan_nr = ccd->chan_nr; + rsl_dec_chan_nr(cdb->chan_nr, &ch_type, &ch_subch, &ch_ts); + if (ccd->h0.h) { + cdb->h = 1; + gsm48_decode_chan_h1(ccd, &cdb->tsc, &cdb->maio, + &cdb->hsn); + LOGP(DRR, LOGL_INFO, " before: (chan_nr 0x%02x MAIO %u " + "HSN %u TS %u SS %u TSC %u)\n", ccd->chan_nr, + cdb->maio, cdb->hsn, ch_ts, ch_subch, cdb->tsc); + } else { + cdb->h = 0; + gsm48_decode_chan_h0(ccd, &cdb->tsc, &cdb->arfcn); + LOGP(DRR, LOGL_INFO, " before: (chan_nr 0x%02x " + "ARFCN %u TS %u SS %u TSC %u)\n", ccd->chan_nr, + cdb->arfcn, ch_ts, ch_subch, cdb->tsc); + } + before_time = 1; + } + + /* decode channel description (after time) */ + cda->chan_nr = ho->chan_desc.chan_nr; + rsl_dec_chan_nr(cda->chan_nr, &ch_type, &ch_subch, &ch_ts); + if (ho->chan_desc.h0.h) { + cda->h = 1; + gsm48_decode_chan_h1(&ho->chan_desc, &cda->tsc, &cda->maio, + &cda->hsn); + LOGP(DRR, LOGL_INFO, " after: (chan_nr 0x%02x MAIO %u HSN %u " + "TS %u SS %u TSC %u)\n", ho->chan_desc.chan_nr, + cda->maio, cda->hsn, ch_ts, ch_subch, cda->tsc); + } else { + cda->h = 0; + gsm48_decode_chan_h0(&ho->chan_desc, &cda->tsc, &cda->arfcn); + LOGP(DRR, LOGL_INFO, " after: (chan_nr 0x%02x ARFCN %u TS %u " + "SS %u TSC %u)\n", ho->chan_desc.chan_nr, + cda->arfcn, ch_ts, ch_subch, cda->tsc); + } + + /* starting time */ +#ifdef TEST_STARTING_TIMER + cda->start = 1; + cda->start_tm.fn = (ms->meas.last_fn + TEST_STARTING_TIMER) % 42432; + LOGP(DRR, LOGL_INFO, " TESTING: starting time ahead\n"); +#else + if (TLVP_PRESENT(&tp, GSM48_IE_START_TIME)) { + gsm48_decode_start_time(cda, (struct gsm48_start_time *) + TLVP_VAL(&tp, GSM48_IE_START_TIME)); + /* 9.1.2.5 "... before time IE is not present..." */ + if (!before_time) { + LOGP(DRR, LOGL_INFO, " -> channel description after " + "time only, but starting time\n"); + } else + LOGP(DRR, LOGL_INFO, " -> channel description before " + "and after time\n"); + } else { + /* 9.1.2.5 "... IEs unnecessary in this message." */ + if (before_time) { + before_time = 0; + LOGP(DRR, LOGL_INFO, " -> channel description before " + "time, but no starting time, ignoring!\n"); + } + } +#endif + + /* mobile allocation / frequency list after time */ + if (cda->h) { + if (TLVP_PRESENT(&tp, GSM48_IE_MA_AFTER)) { + const uint8_t *lv = + TLVP_VAL(&tp, GSM48_IE_MA_AFTER) - 1; + + LOGP(DRR, LOGL_INFO, " after: hopping required and " + "mobile allocation available\n"); + if (*lv + 1 > sizeof(cda->mob_alloc_lv)) { + LOGP(DRR, LOGL_ERROR, "Error: no LV space!\n"); + return -ENOMEM; + } + memcpy(&cda->mob_alloc_lv, lv, *lv + 1); + } else + if (TLVP_PRESENT(&tp, GSM48_IE_FREQ_L_AFTER)) { + const uint8_t *lv = + TLVP_VAL(&tp, GSM48_IE_FREQ_L_AFTER) - 1; + + LOGP(DRR, LOGL_INFO, " after: hopping required and " + "frequency list available\n"); + if (*lv + 1 > sizeof(cda->freq_list_lv)) { + LOGP(DRR, LOGL_ERROR, "Error: no LV space!\n"); + return -ENOMEM; + } + memcpy(&cda->freq_list_lv, lv, *lv + 1); + } else { + LOGP(DRR, LOGL_NOTICE, " after: hopping required, but " + "no mobile allocation / frequency list\n"); + } + } + + /* mobile allocation / frequency list before time */ + if (cdb->h) { + if (TLVP_PRESENT(&tp, GSM48_IE_MA_BEFORE)) { + const uint8_t *lv = + TLVP_VAL(&tp, GSM48_IE_MA_BEFORE) - 1; + + LOGP(DRR, LOGL_INFO, " before: hopping required and " + "mobile allocation available\n"); + if (*lv + 1 > sizeof(cdb->mob_alloc_lv)) { + LOGP(DRR, LOGL_ERROR, "Error: no LV space!\n"); + return -ENOMEM; + } + memcpy(&cdb->mob_alloc_lv, lv, *lv + 1); + } else + if (TLVP_PRESENT(&tp, GSM48_IE_FREQ_L_BEFORE)) { + const uint8_t *lv = + TLVP_VAL(&tp, GSM48_IE_FREQ_L_BEFORE) - 1; + + LOGP(DRR, LOGL_INFO, " before: hopping required and " + "frequency list available\n"); + if (*lv + 1 > sizeof(cdb->freq_list_lv)) { + LOGP(DRR, LOGL_ERROR, "Error: no LV space!\n"); + return -ENOMEM; + } + memcpy(&cdb->freq_list_lv, lv, *lv + 1); + } else + if (TLVP_PRESENT(&tp, GSM48_IE_F_CH_SEQ_BEFORE)) { + const uint8_t *lv = + TLVP_VAL(&tp, GSM48_IE_F_CH_SEQ_BEFORE) - 1; + + LOGP(DRR, LOGL_INFO, " before: hopping required and " + "frequency channel sequence available\n"); + if (*lv + 1 > sizeof(cdb->freq_seq_lv)) { + LOGP(DRR, LOGL_ERROR, "Error: no LV space!\n"); + return -ENOMEM; + } + memcpy(&cdb->freq_seq_lv, lv, *lv + 1); + } else + if (cda->mob_alloc_lv[0]) { + LOGP(DRR, LOGL_INFO, " before: hopping required and " + "mobile allocation not available, using " + "mobile allocation after time\n"); + memcpy(&cdb->mob_alloc_lv, &cda->mob_alloc_lv, + sizeof(cdb->mob_alloc_lv)); + if (cda->freq_list_lv[0]) { + LOGP(DRR, LOGL_INFO, " before: hopping required and " + "frequency list not available, using " + "frequency list after time\n"); + memcpy(&cdb->freq_list_lv, &cda->freq_list_lv, + sizeof(cdb->freq_list_lv)); + } else { + LOGP(DRR, LOGL_NOTICE, " before: hopping required, but " + "no mobile allocation / frequency list\n"); + } + } + + /* cell channel description */ + if (TLVP_PRESENT(&tp, GSM48_IE_CELL_CH_DESC)) { + const uint8_t *lv = TLVP_VAL(&tp, GSM48_IE_CELL_CH_DESC) - 1; + + LOGP(DRR, LOGL_INFO, " both: using cell channel description " + "in case of mobile allocation\n"); + if (*lv + 1 > sizeof(cdb->cell_desc_lv)) { + LOGP(DRR, LOGL_ERROR, "Error: no LV space!\n"); + return -ENOMEM; + } + memcpy(&cdb->cell_desc_lv, lv, *lv + 1); + memcpy(&cda->cell_desc_lv, lv, *lv + 1); + } else { + /* keep old */ + memcpy(&cdb->cell_desc_lv, &rr->cd_now.cell_desc_lv, + sizeof(cdb->cell_desc_lv)); + memcpy(&cda->cell_desc_lv, &rr->cd_now.cell_desc_lv, + sizeof(cda->cell_desc_lv)); + } + + /* channel mode */ + if (TLVP_PRESENT(&tp, GSM48_IE_CHANMODE_1)) { + cda->mode = cdb->mode = *TLVP_VAL(&tp, GSM48_IE_CHANMODE_1); + LOGP(DRR, LOGL_INFO, " both: changing channel mode 0x%02x\n", + cda->mode); + } else + cda->mode = cdb->mode = rr->cd_now.mode; + + /* cipher mode setting */ + if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET)) + cda->cipher = cdb->cipher = + *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET); + LOGP(DRR, LOGL_INFO, " both: changing cipher mode 0x%02x\n", + cda->cipher); + } else + cda->cipher = cdb->cipher = rr->cd_now.cipher; + + /* power command and TA (before and after time) */ + gsm48_decode_power_cmd_acc( + (struct gsm48_power_cmd *) &ho->power_command, + &cda->ind_tx_power, &rr->hando_act); + cdb->ind_tx_power = cda->ind_tx_power; + cda->ind_ta = cdb->ind_ta = rr->cd_now.ind_ta; /* same cell */ + LOGP(DRR, LOGL_INFO, " both: (tx_power %d TA %d access=%s)\n", + cda->ind_tx_power, cda->ind_ta, + (rr->hando_act) ? "optional" : "mandatory"); + + /* check if we have to change channel at starting time */ + if (cda->start) { + int32_t now, start, diff; + + /* how much time do we have left? */ + now = ms->meas.last_fn % 42432; + start = cda->start_tm.fn % 42432; + diff = start - now; + if (diff < 0) + diff += 42432; + LOGP(DRR, LOGL_INFO, " after: (Tnow %d Tstart %d diff %d)\n", + now, start, diff); + start_mili = (uint32_t)diff * 19580 / 42432 * 10; + if (diff >= 32024 || !start_mili) { + LOGP(DRR, LOGL_INFO, " -> Start time already " + "elapsed\n"); + before_time = 0; + cda->start = 0; + } else { + LOGP(DRR, LOGL_INFO, " -> Start time is %d ms in the " + "future\n", start_mili); + } + } + + /* check if channels are valid */ + if (before_time) { + cause = gsm48_rr_render_ma(ms, cdb, ma, &ma_len); + if (cause) + return gsm48_rr_tx_hando_fail(ms, cause); + } + cause = gsm48_rr_render_ma(ms, cda, ma, &ma_len); + if (cause) + return gsm48_rr_tx_hando_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 + +#ifdef TEST_FREQUENCY_MOD + LOGP(DRR, LOGL_INFO, " TESTING: frequency modify HANDO.CMD\n"); + before_time = 1; + memcpy(cdb, cda, sizeof(*cdb)); + cdb->h = 0; + cdb->arfcn = 0; +#endif + + /* schedule start of handover */ + rr->modify_state = GSM48_RR_MOD_HANDO; + if (!before_time && cda->start) { + start_rr_t_starting(rr, start_mili / 1000, start_mili % 1000); + /* when timer fires, start time is already elapsed */ + cda->start = 0; + + return 0; + } + + /* if no starting time, start suspension of current link directly */ + LOGP(DRR, LOGL_INFO, "request suspension of data link\n"); + nmsg = gsm48_l3_msgb_alloc(); + if (!nmsg) + return -ENOMEM; + gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg); + + return 0; +} + +/* send all queued messages down to layer 2 */ +static int gsm48_rr_dequeue_down(struct osmocom_ms *ms) +{ + struct gsm48_rrlayer *rr = &ms->rrlayer; + struct msgb *msg; + + while((msg = msgb_dequeue(&rr->downqueue))) { + LOGP(DRR, LOGL_INFO, "Sending queued message.\n"); + gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg); + } + + return 0; +} + +/* channel is resumed in dedicated mode */ +static int gsm48_rr_estab_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm48_rrlayer *rr = &ms->rrlayer; + + 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); + + rr->modify_state = GSM48_RR_MOD_NONE; + + return 0; +} + +/* suspend confirm in dedicated mode */ +static int gsm48_rr_susp_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm48_rrlayer *rr = &ms->rrlayer; + + if (rr->modify_state) { + struct msgb *nmsg; + uint16_t ma[64]; + uint8_t ma_len; + + /* deactivating dedicated mode */ + LOGP(DRR, LOGL_INFO, "suspension coplete, leaving dedicated " + "mode\n"); + l1ctl_tx_dm_rel_req(ms); + l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED); + + /* store current channel descriptions */ + memcpy(&rr->cd_last, &rr->cd_now, sizeof(rr->cd_last)); + + /* copy channel description "after time" */ + memcpy(&rr->cd_now, &rr->cd_after, sizeof(rr->cd_now)); + + if (rr->cd_after.start) { + /* render channel "before time" */ + gsm48_rr_render_ma(ms, &rr->cd_before, ma, &ma_len); + + /* activate channel */ + gsm48_rr_activate_channel(ms, &rr->cd_before, ma, + ma_len); + + /* render channel "after time" */ + gsm48_rr_render_ma(ms, &rr->cd_now, ma, &ma_len); + + /* schedule change of channel */ + gsm48_rr_channel_after_time(ms, &rr->cd_now, ma, ma_len, + rr->cd_now.start_tm.fn); + } else { + /* render channel "after time" */ + gsm48_rr_render_ma(ms, &rr->cd_now, ma, &ma_len); + + /* activate channel */ + gsm48_rr_activate_channel(ms, &rr->cd_now, ma, ma_len); + } + + /* 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); + +#ifdef TODO + /* trigger RACH */ + if (rr->modify_state == GSM48_RR_MOD_HANDO) { + gsm48_rr_tx_hando_access(ms); + rr->hando_acc_left = 3; + } +#endif + } + return 0; +} + +/* + * radio ressource requests + */ + +/* establish request for dedicated mode */ +static int gsm48_rr_est_req(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm48_rrlayer *rr = &ms->rrlayer; + struct gsm322_cellsel *cs = &ms->cellsel; + struct gsm48_sysinfo *s = cs->si; + struct gsm_subscriber *subscr = &ms->subscr; + struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data; + struct gsm48_hdr *gh = msgb_l3(msg); + uint8_t cause; + struct msgb *nmsg; struct gsm48_rr_hdr *nrrh; uint16_t acc_class; @@ -3701,7 +4436,8 @@ static int gsm48_rr_data_req(struct osmocom_ms *ms, struct msgb *msg) gsm48_apply_v_sd(rr, msg); /* queue message, during handover or assignment procedure */ - if (rr->hando_susp_state || rr->assign_susp_state) { + if (rr->modify_state == GSM48_RR_MOD_ASSIGN + || rr->modify_state == GSM48_RR_MOD_HANDO) { LOGP(DRR, LOGL_INFO, "Queueing message during suspend.\n"); msgb_enqueue(&rr->downqueue, msg); return 0; @@ -3746,17 +4482,18 @@ static int gsm48_rr_data_ind(struct osmocom_ms *ms, struct msgb *msg) case GSM48_MT_RR_CHAN_MODE_MODIF: rc = gsm48_rr_rx_chan_modify(ms, msg); break; -#if 0 case GSM48_MT_RR_HANDO_CMD: rc = gsm48_rr_rx_hando_cmd(ms, msg); break; case GSM48_MT_RR_FREQ_REDEF: - rc = gsm48_rr_rx_freq_redef(ms, msg); + rc = gsm48_rr_rx_frq_redef(ms, msg); break; -#endif case GSM48_MT_RR_CHAN_REL: rc = gsm48_rr_rx_chan_rel(ms, msg); break; + case GSM48_MT_RR_APP_INFO: + LOGP(DRR, LOGL_NOTICE, "APP INFO not supported!\n"); + break; default: LOGP(DRR, LOGL_NOTICE, "Message type 0x%02x unknown.\n", gh->msg_type); @@ -4020,6 +4757,81 @@ static int gsm48_rr_rel_cnf(struct osmocom_ms *ms, struct msgb *msg) return 0; } +/* MDL-ERROR */ +static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm48_rrlayer *rr = &ms->rrlayer; + struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); + struct msgb *nmsg; + 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: + case RLL_CAUSE_UNSOL_DM_RESP_MF: + break; + default: + LOGP(DRR, LOGL_NOTICE, "MDL-Error (cause %d) ignoring\n", + cause); + } + + LOGP(DRR, LOGL_NOTICE, "MDL-Error (cause %d) aborting\n", cause); + + /* disconnect the main signalling link */ + nmsg = gsm48_l3_msgb_alloc(); + if (!nmsg) + return -ENOMEM; + mode = msgb_put(nmsg, 2); + mode[0] = RSL_IE_RELEASE_MODE; + mode[1] = 1; /* local release */ + gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg); + + /* deactivate channel */ + l1ctl_tx_dm_rel_req(ms); + 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; + } + + /* send abort ind to upper layer */ + nmsg = gsm48_rr_msgb_alloc(GSM48_RR_ABORT_IND); + if (!nmsg) + return -ENOMEM; + nrrh = (struct gsm48_rr_hdr *)nmsg->data; + nrrh->cause = RR_REL_CAUSE_LINK_FAILURE; + gsm48_rr_upmsg(ms, nmsg); + + /* return idle */ + new_rr_state(rr, GSM48_RR_ST_IDLE); + return 0; +} + /* * state machines */ @@ -4065,10 +4877,10 @@ static struct dldatastate { #if 0 {SBIT(GSM48_RR_ST_DEDICATED), RSL_MT_CHAN_CNF, gsm48_rr_rand_acc_cnf_dedicated}, - - {SBIT(GSM_RRSTATE), - RSL_MT_MDL_ERROR_IND, gsm48_rr_mdl_error_ind}, #endif + + {SBIT(GSM48_RR_ST_DEDICATED), + RSL_MT_ERROR_IND, gsm48_rr_mdl_error_ind}, }; #define DLDATASLLEN \ @@ -4173,11 +4985,6 @@ static struct rrdownstate { {SBIT(GSM48_RR_ST_CONN_PEND) | SBIT(GSM48_RR_ST_DEDICATED), /* 3.4.13.3 */ GSM48_RR_ABORT_REQ, gsm48_rr_abort_req}, - -#if 0 - {SBIT(GSM48_RR_ST_DEDICATED), - GSM48_RR_ACT_REQ, gsm48_rr_act_req}, -#endif }; #define RRDOWNSLLEN \ @@ -4256,9 +5063,11 @@ int gsm48_rr_exit(struct osmocom_ms *ms) } stop_rr_t_monitor(rr); + stop_rr_t_starting(rr); stop_rr_t_rel_wait(rr); stop_rr_t3110(rr); stop_rr_t3122(rr); + stop_rr_t3124(rr); stop_rr_t3126(rr); return 0; @@ -4269,109 +5078,6 @@ int gsm48_rr_exit(struct osmocom_ms *ms) todo rr_sync_ind when receiving ciph, re ass, channel mode modify -/* decode "Cell Description" (10.5.2.2) */ -static int gsm48_decode_cell_desc(struct gsm48_cell_desc *cd, uint16_t *arfcn, uint8_t *ncc uint8_t *bcc) -{ - *arfcn = (cd->bcch_hi << 8) + cd->bcch_lo; - *ncc = cd->ncc; - *bcc = cd->bcc; -} - -/* decode "Synchronization Indication" (10.5.2.39) */ -static int gsm48_decode_sync_ind(struct gsm48_rrlayer *rr, struct gsm48_rr_sync_ind *si) -{ - rr->ho_sync_ind = si->si; - rr->ho_rot = si->rot; - rr->ho_nci = si->nci; -} - -/* receiving HANDOVER COMMAND message (9.1.15) */ -static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg) -{ - struct gsm48_rrlayer *rr = ms->rrlayer; - struct gsm48_hdr *gh = msgb_l3(msg); - struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *)gh->data; - int payload_len = msgb_l3len(msg) - sizeof(*gh) - wirklich sizeof(*ho); - struct tlv_parsed tp; - struct gsm48_rr_cd cd; - struct msgb *nmsg; - - memset(&cd, 0, sizeof(cd)); - - if (payload_len < 0) { - LOGP(DRR, LOGL_NOTICE, "Short read of HANDOVER COMMAND message.\n"); - return gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC); - } - tlv_parse(&tp, &gsm48_rr_att_tlvdef, ho->data, payload_len, 0, 0); - -TODO - - /* start suspension of current link */ - nmsg = gsm48_l3_msgb_alloc(); - if (!nmsg) - return -ENOMEM; - gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg); - - /* change into special handover suspension state */ - rr->hando_susp_state = 1; - rr->resume_last_state = 0; - - return 0; -} - -static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg) -{ - struct gsm48_rrlayer *rr = ms->rrlayer; - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - struct msgb *nmsg; - uint8_t cause = rllh->data[2]; - - printing of the cause - - switch (cause) { - case RLL_CAUSE_SEQ_ERR: - case RLL_CAUSE_UNSOL_DM_RESP_MF: - einige muessen ignoriert werden - andere gelten als release - } - - if (rr->hando_susp_state || rr->assign_susp_state) { - if (!rr->resume_last_state) { - uint16_t ma[64]; - uint8_t ma_len; - - rr->resume_last_state = 1; - - /* get old channel description */ - memcpy(&rr->cd_now, &rr->chan_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); - } - rr->resume_last_state = 0; - } - - /* deactivate channel */ - l1ctl_tx_dm_rel_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr); - - /* send abort ind to upper layer */ - nmsg = gsm48_mm_msgb_alloc(); - - if (!msg) - return -ENOMEM; - nrrh = (struct gsm_mm_hdr *)nmsg->data; - nrrh->msg_type = RR_ABORT_IND; - nrrh->cause = GSM_MM_CAUSE_LINK_FAILURE; - return gsm48_rr_upmsg(ms, msg); -} - static void timeout_rr_t3124(void *arg) { struct gsm48_rrlayer *rr = arg; @@ -4381,7 +5087,7 @@ static void timeout_rr_t3124(void *arg) hando_acc_left = 0; /* get old channel description */ - memcpy(&rr->chan_desc, &rr->chan_last, sizeof(*cd)); + memcpy(&rr->chan_desc, &rr->chan_last, sizeof(rr->chan_desc)); /* change radio to old channel */ tx_ph_dm_est_req(ms, rr->cd_now.arfcn, rr->cd_now.chan_nr, @@ -4414,7 +5120,7 @@ static int gsm48_rr_rand_acc_cnf_dedicated(struct osmocom_ms *ms, struct msgb *m struct msgb *nmsg; int s; - if (!rr->hando_susp_state) { + if (rr->modify_state != GSM48_RR_MOD_HANDO) { LOGP(DRR, LOGL_NOTICE, "Random acces confirm, but not in handover state.\n"); return 0; }