summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/host/layer23/include/osmocom/bb/common/osmocom_data.h2
-rw-r--r--src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h17
-rw-r--r--src/host/layer23/src/common/l1ctl.c2
-rw-r--r--src/host/layer23/src/mobile/gsm48_rr.c873
4 files changed, 580 insertions, 314 deletions
diff --git a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
index dc7ba11d..2fa59f7b 100644
--- a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
+++ b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
@@ -27,7 +27,9 @@ struct osmol2_entity {
/* RX measurement statistics */
struct rx_meas_stat {
+ uint32_t last_fn;
uint32_t frames;
+ uint32_t snr;
uint32_t berr;
uint32_t rxlev;
};
diff --git a/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h b/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
index f88d7a9a..c7035055 100644
--- a/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
+++ b/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
@@ -69,9 +69,16 @@ struct gsm48_rr_cd {
uint8_t hsn;
uint8_t chan_nr; /* type, slot, sub slot */
uint8_t link_id;
- uint8_t ta; /* timing advance */
+ uint8_t ind_tx_power; /* last indicated power */
+ uint8_t ind_ta; /* last indicated ta */
uint8_t mob_alloc_lv[9]; /* len + up to 64 bits */
- uint8_t start_t1, start_t2, start_t3; /* start. time */
+ uint8_t freq_list_lv[131]; /* len + 130 octets */
+ uint8_t freq_seq_lv[10]; /* len + 9 octets */
+ uint8_t cell_desc_lv[17]; /* len + 16 octets */
+ uint8_t start; /* start time available */
+ struct gsm_time start_tm; /* start time */
+ uint8_t mode; /* mode of channel */
+ uint8_t cipher; /* ciphering of channel */
};
/* measurements */
@@ -146,12 +153,12 @@ struct gsm48_rrlayer {
uint8_t hando_susp_state;
uint8_t assign_susp_state;
uint8_t resume_last_state;
- struct gsm48_rr_cd cd_last;
+ struct gsm48_rr_cd cd_last; /* store last cd in case of failure */
+ struct gsm48_rr_cd cd_before; /* before start time */
+ struct gsm48_rr_cd cd_after; /* after start time */
/* measurements */
struct gsm48_rr_meas meas;
- uint8_t ind_tx_power; /* last indicated power */
- uint8_t ind_ta; /* last indicated ta */
/* BA range */
uint8_t ba_ranges;
diff --git a/src/host/layer23/src/common/l1ctl.c b/src/host/layer23/src/common/l1ctl.c
index 2aa3ab5a..835de5d3 100644
--- a/src/host/layer23/src/common/l1ctl.c
+++ b/src/host/layer23/src/common/l1ctl.c
@@ -149,7 +149,9 @@ static int rx_ph_data_ind(struct osmocom_ms *ms, struct msgb *msg)
rsl_chan_nr_str(dl->chan_nr), tm.t1, tm.t2, tm.t3,
hexdump(ccch->data, sizeof(ccch->data)));
+ meas->last_fn = ntohl(dl->frame_nr);
meas->frames++;
+ meas->snr += dl->snr;
meas->berr += dl->num_biterr;
meas->rxlev += dl->rx_level;
diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c
index 46993d82..0e4c2dea 100644
--- a/src/host/layer23/src/mobile/gsm48_rr.c
+++ b/src/host/layer23/src/mobile/gsm48_rr.c
@@ -86,30 +86,6 @@ int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc,
return 0;
}
-static int gsm48_encode_chan_h0(struct gsm48_chan_desc *cd, uint8_t tsc,
- uint16_t arfcn)
-{
- cd->h0.tsc = tsc;
- cd->h0.h = 0;
- cd->h0.arfcn_low = arfcn & 0xff;
- cd->h0.arfcn_high = arfcn >> 8;
-
- return 0;
-}
-
-static int gsm48_encode_chan_h1(struct gsm48_chan_desc *cd, uint8_t tsc,
- uint8_t maio, uint8_t hsn)
-{
- cd->h1.tsc = tsc;
- cd->h1.h = 1;
- cd->h1.maio_low = maio & 0x03;
- cd->h1.maio_high = maio >> 2;
- cd->h1.hsn = hsn;
-
- return 0;
-}
-
-
static int gsm48_decode_chan_h0(struct gsm48_chan_desc *cd, uint8_t *tsc,
uint16_t *arfcn)
{
@@ -129,13 +105,26 @@ static int gsm48_decode_chan_h1(struct gsm48_chan_desc *cd, uint8_t *tsc,
return 0;
}
+/* decode "Power Command" (10.5.2.28) and (10.5.2.28a) */
+static int gsm48_decode_power_cmd_acc(struct gsm48_power_cmd *pc,
+ uint8_t *power_level, uint8_t *atc)
+{
+ *power_level = pc->power_level;
+ if (atc) /* only in case of 10.5.2.28a */
+ *atc = pc->atc;
+
+ return 0;
+}
+
/* 10.5.2.38 decode Starting time IE */
static int gsm48_decode_start_time(struct gsm48_rr_cd *cd,
struct gsm48_start_time *st)
{
- cd->start_t1 = st->t1;
- cd->start_t2 = st->t2;
- cd->start_t3 = (st->t3_high << 3) | st->t3_low;
+ cd->start = 1;
+ cd->start_tm.t1 = st->t1;
+ cd->start_tm.t2 = st->t2;
+ cd->start_tm.t3 = (st->t3_high << 3) | st->t3_low;
+ cd->start_tm.fn = gsm_gsmtime2fn(&cd->start_tm);
return 0;
}
@@ -262,6 +251,12 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state)
LOGP(DRR, LOGL_INFO, "new state %s -> %s\n",
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;
+ }
+
rr->state = state;
if (state == GSM48_RR_ST_IDLE) {
@@ -469,7 +464,7 @@ static void timeout_rr_monitor(void *arg)
struct gsm322_cellsel *cs = &rr->ms->cellsel;
struct rx_meas_stat *meas = &rr->ms->meas;
struct gsm_settings *set = &rr->ms->settings;
- int rxlev, berr;
+ int rxlev, berr, snr;
uint8_t ch_type, ch_subch, ch_ts;
char text[256];
@@ -480,17 +475,19 @@ static void timeout_rr_monitor(void *arg)
} else {
rxlev = meas->rxlev / meas->frames;
berr = meas->berr / meas->frames;
- sprintf(text, "MON: arfcn=%d lev=%s ber=%2d LAI=%s %s %04x "
- "ID=%04x", cs->sel_arfcn, gsm_print_rxlev(rxlev),
- berr, gsm_print_mcc(cs->sel_mcc),
+ snr = meas->snr / meas->frames;
+ sprintf(text, "MON: arfcn=%d lev=%s snr=%2d ber=%2d "
+ "LAI=%s %s %04x ID=%04x", cs->sel_arfcn,
+ gsm_print_rxlev(rxlev), berr, snr,
+ gsm_print_mcc(cs->sel_mcc),
gsm_print_mnc(cs->sel_mnc), cs->sel_lac, cs->sel_id);
if (rr->state == GSM48_RR_ST_DEDICATED) {
rsl_dec_chan_nr(rr->cd_now.chan_nr, &ch_type,
&ch_subch, &ch_ts);
sprintf(text + strlen(text), " TA=%d pwr=%d TS=%d",
- rr->ind_ta - set->alter_delay,
+ rr->cd_now.ind_ta - set->alter_delay,
(set->alter_tx_power) ? set->alter_tx_power_value
- : rr->ind_tx_power, ch_ts);
+ : rr->cd_now.ind_tx_power, ch_ts);
if (ch_type == RSL_CHAN_SDCCH8_ACCH
|| ch_type == RSL_CHAN_SDCCH4_ACCH)
sprintf(text + strlen(text), "/%d", ch_subch);
@@ -1335,8 +1332,8 @@ int gsm48_rr_tx_rand_acc(struct osmocom_ms *ms, struct msgb *msg)
ncch->data[7] = tx_power;
/* set initial indications */
- rr->ind_tx_power = s->ms_txpwr_max_cch;
- rr->ind_ta = set->alter_delay;
+ rr->cd_now.ind_tx_power = s->ms_txpwr_max_cch;
+ rr->cd_now.ind_ta = set->alter_delay;
/* store ra until confirmed, then copy it with time into cr_hist */
rr->cr_ra = chan_req;
@@ -1414,7 +1411,7 @@ static int gsm48_decode_ccd(struct gsm48_sysinfo *s,
}
/* decode "Mobile Allocation" (10.5.2.21) */
-static int gsm48_decode_mobile_alloc(struct gsm48_sysinfo *s,
+static int gsm48_decode_mobile_alloc(struct gsm_sysinfo_freq *freq,
uint8_t *ma, uint8_t len, uint16_t *hopping, uint8_t *hopp_len, int si4)
{
int i, j = 0;
@@ -1428,12 +1425,12 @@ static int gsm48_decode_mobile_alloc(struct gsm48_sysinfo *s,
*hopp_len = 0;
if (si4) {
for (i = 0; i < 1024; i++)
- s->freq[i].mask &= ~FREQ_TYPE_HOPP;
+ freq[i].mask &= ~FREQ_TYPE_HOPP;
}
/* generating list of all frequencies (1..1023,0) */
for (i = 1; i <= 1024; i++) {
- if ((s->freq[i & 1023].mask & FREQ_TYPE_SERV)) {
+ if ((freq[i & 1023].mask & FREQ_TYPE_SERV)) {
LOGP(DRR, LOGL_INFO, "Serving cell ARFCN #%d: %d\n",
j, i & 1023);
f[j++] = i & 1023;
@@ -1460,7 +1457,7 @@ static int gsm48_decode_mobile_alloc(struct gsm48_sysinfo *s,
}
hopping[(*hopp_len)++] = f[i];
if (si4)
- s->freq[f[i]].mask |= FREQ_TYPE_HOPP;
+ freq[f[i]].mask |= FREQ_TYPE_HOPP;
}
}
@@ -1857,8 +1854,8 @@ static int gsm48_rr_rx_sysinfo4(struct osmocom_ms *ms, struct msgb *msg)
if (payload_len >= 1 && data[0] == GSM48_IE_CBCH_MOB_AL) {
if (payload_len < 1 || payload_len < 2 + data[1])
goto short_read;
- gsm48_decode_mobile_alloc(s, data + 2, si->data[1], s->hopping,
- &s->hopp_len, 1);
+ gsm48_decode_mobile_alloc(s->freq, data + 2, si->data[1],
+ s->hopping, &s->hopp_len, 1);
payload_len -= 2 + data[1];
data += 2 + data[1];
}
@@ -2384,7 +2381,7 @@ static int gsm48_rr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
/* channel description */
memcpy(&rr->cd_now, &cd, sizeof(rr->cd_now));
/* timing advance */
- rr->cd_now.ta = ia->timing_advance;
+ rr->cd_now.ind_ta = ia->timing_advance;
/* mobile allocation */
memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len,
ia->mob_alloc_len + 1);
@@ -2493,7 +2490,7 @@ static int gsm48_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg)
/* channel description */
memcpy(&rr->cd_now, &cd1, sizeof(rr->cd_now));
/* timing advance */
- rr->cd_now.ta = ia->timing_advance1;
+ rr->cd_now.ind_ta = ia->timing_advance1;
/* mobile allocation */
memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len,
ia->mob_alloc_len + 1);
@@ -2505,7 +2502,7 @@ static int gsm48_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct msgb *msg)
/* channel description */
memcpy(&rr->cd_now, &cd2, sizeof(rr->cd_now));
/* timing advance */
- rr->cd_now.ta = ia->timing_advance2;
+ rr->cd_now.ind_ta = ia->timing_advance2;
/* mobile allocation */
memcpy(&rr->cd_now.mob_alloc_lv, &ia->mob_alloc_len,
ia->mob_alloc_len + 1);
@@ -2723,30 +2720,186 @@ int gsm48_rr_los(struct osmocom_ms *ms)
return 0;
}
+/* activation of channel in dedicated mode */
+static int gsm48_rr_activate_channel(struct osmocom_ms *ms,
+ struct gsm48_rr_cd *cd, uint16_t *ma, uint8_t ma_len)
+{
+ 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);
+ l1ctl_tx_param_req(ms, cd->ind_ta - set->alter_delay,
+ (set->alter_tx_power) ? set->alter_tx_power_value
+ : cd->ind_tx_power);
+
+ /* establish */
+ LOGP(DRR, LOGL_INFO, "establishing channel in dedicated mode\n");
+ rsl_dec_chan_nr(cd->chan_nr, &ch_type, &ch_subch, &ch_ts);
+ if ((ch_type != RSL_CHAN_SDCCH8_ACCH
+ && ch_type != RSL_CHAN_SDCCH4_ACCH
+ && ch_type != RSL_CHAN_Bm_ACCHs) /*|| ch_ts > 4*/ || ch_subch >= 4) {
+ printf("Channel type %d, subch %d, ts %d not supported, "
+ "exitting.\n", ch_type, ch_subch, ch_ts);
+ exit(-ENOTSUP);
+ }
+ if (cd->h)
+ l1ctl_tx_dm_est_req_h1(ms, cd->maio, cd->hsn,
+ ma, ma_len, cd->chan_nr, cd->tsc);
+ else
+ l1ctl_tx_dm_est_req_h0(ms, cd->arfcn, cd->chan_nr, cd->tsc);
+
+#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)
+{
+ struct gsm48_sysinfo *s = ms->cellsel.si;
+ struct gsm_support *sup = &ms->support;
+ int i;
+ uint16_t arfcn;
+
+ /* no hopping (no MA), channel description is valid */
+ if (!cd->h) {
+ ma_len = 0;
+ return 0;
+ }
+
+ /* decode mobile allocation */
+ if (cd->mob_alloc_lv[0]) {
+ struct gsm_sysinfo_freq *freq = s->freq;
+
+ LOGP(DRR, LOGL_INFO, "decoding mobile allocation\n");
+
+ if (cd->cell_desc_lv[0]) {
+ LOGP(DRR, LOGL_INFO, "using cell channel descr.\n");
+ if (cd->cell_desc_lv[0] != 16) {
+ LOGP(DRR, LOGL_ERROR, "cell channel descr. "
+ "has invalid lenght\n");
+ return GSM48_RR_CAUSE_ABNORMAL_UNSPEC;
+ }
+ gsm48_decode_freq_list(freq, cd->cell_desc_lv + 1, 16,
+ 0xce, FREQ_TYPE_SERV);
+ }
+
+ gsm48_decode_mobile_alloc(freq, cd->mob_alloc_lv + 1,
+ 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;
+ }
+ } else
+ /* decode frequency list */
+ if (cd->freq_list_lv[0]) {
+ struct gsm_sysinfo_freq f[1024];
+ int j = 0;
+
+ LOGP(DRR, LOGL_INFO, "decoding frequency list\n");
+
+ /* get bitmap */
+ if (gsm48_decode_freq_list(f, cd->freq_list_lv + 1,
+ cd->freq_list_lv[0], 0xce, FREQ_TYPE_SERV)) {
+ LOGP(DRR, LOGL_NOTICE, "frequency list invalid\n");
+ return GSM48_RR_CAUSE_ABNORMAL_UNSPEC;
+ }
+
+ /* collect channels from bitmap (1..1023,0) */
+ for (i = 1; i <= 1024; i++) {
+ if ((f[i & 1023].mask & FREQ_TYPE_SERV)) {
+ LOGP(DRR, LOGL_INFO, "Listed ARFCN #%d: %d\n",
+ j, i);
+ if (j == 64) {
+ LOGP(DRR, LOGL_NOTICE, "frequency list "
+ "exceeds 64 entries!\n");
+ return GSM48_RR_CAUSE_ABNORMAL_UNSPEC;
+ }
+ ma[j++] = i;
+ }
+ }
+ *ma_len = j;
+ return 0;
+ } else
+ /* decode frequency channel sequence */
+ if (cd->freq_seq_lv[0]) {
+ int j = 0, inc;
+
+ LOGP(DRR, LOGL_INFO, "decoding frequency channel sequence\n");
+
+ if (cd->freq_seq_lv[0] != 9) {
+ LOGP(DRR, LOGL_NOTICE, "invalid frequency channel "
+ "sequence\n");
+ return GSM48_RR_CAUSE_ABNORMAL_UNSPEC;
+ }
+ arfcn = cd->freq_seq_lv[1] & 0x7f;
+ LOGP(DRR, LOGL_INFO, "Listed Sequence ARFCN #%d: %d\n", j,
+ arfcn);
+ ma[j++] = arfcn;
+ for (i = 0; i <= 16; i++) {
+ if ((i & 1))
+ inc = cd->freq_seq_lv[2 + (i >> 1)] & 0x0f;
+ else
+ inc = cd->freq_seq_lv[2 + (i >> 1)] >> 4;
+ if (inc) {
+ arfcn += inc;
+ LOGP(DRR, LOGL_INFO, "Listed Sequence ARFCN "
+ "#%d: %d\n", j, arfcn);
+ ma[j++] = arfcn;
+ } else
+ arfcn += 15;
+ }
+ *ma_len = j;
+ return 0;
+ } else {
+ LOGP(DRR, LOGL_NOTICE, "hopping, but nothing that tells us "
+ "a sequence\n");
+ return GSM48_RR_CAUSE_ABNORMAL_UNSPEC;
+ }
+
+ /* check for unsported frequency */
+ for (i = 0; i < *ma_len; i++) {
+ arfcn = ma[i];
+ if (!(sup->freq_map[arfcn >> 3] & (1 << (arfcn & 7)))) {
+ LOGP(DRR, LOGL_NOTICE, "Hopping frequency %d not "
+ "supported\n", arfcn);
+ return GSM48_RR_CAUSE_FREQ_NOT_IMPL;
+ }
+ }
+
+#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;
+}
+
/* activate link and send establish request */
static int gsm48_rr_dl_est(struct osmocom_ms *ms)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm48_sysinfo *s = cs->si;
- struct gsm_settings *set = &ms->settings;
struct msgb *nmsg;
struct gsm48_hdr *gh;
struct gsm48_pag_rsp *pr;
uint8_t mi[11];
- uint8_t ch_type, ch_subch, ch_ts;
uint16_t ma[64];
uint8_t ma_len;
- if (rr->cd_now.h) {
- gsm48_decode_mobile_alloc(s, rr->cd_now.mob_alloc_lv + 1,
- rr->cd_now.mob_alloc_lv[0], ma, &ma_len, 0);
- if (ma_len < 1) {
- LOGP(DRR, LOGL_NOTICE, "Hopping, but no allocation\n");
- return -EINVAL;
- }
- }
+ /* get hopping sequence, if required */
+ if (gsm48_rr_render_ma(ms, &rr->cd_now, ma, &ma_len))
+ return -EINVAL;
/* 3.3.1.1.3.1 */
stop_rr_t3126(rr);
@@ -2797,38 +2950,8 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms)
memcpy(pr->data, mi + 1, 1 + mi[1]);
}
- /* reset scheduler */
- LOGP(DRR, LOGL_INFO, "resetting scheduler\n");
- l1ctl_tx_reset_req(ms, L1CTL_RES_T_SCHED);
-
- /* setting (new) timing advance */
- rr->ind_ta = rr->cd_now.ta;
- LOGP(DRR, LOGL_INFO, "setting indicated TA %d (actual TA %d)\n",
- rr->ind_ta, rr->ind_ta - set->alter_delay);
- l1ctl_tx_param_req(ms, rr->ind_ta - set->alter_delay,
- (set->alter_tx_power) ? set->alter_tx_power_value
- : rr->ind_tx_power);
-
/* activate channel */
- LOGP(DRR, LOGL_INFO, "activating channel\n");
-#ifdef TODO
- RSL_MT_ to activate channel with all the cd_now informations
-#else
- rsl_dec_chan_nr(rr->cd_now.chan_nr, &ch_type, &ch_subch, &ch_ts);
- if ((ch_type != RSL_CHAN_SDCCH8_ACCH
- && ch_type != RSL_CHAN_SDCCH4_ACCH
- && ch_type != RSL_CHAN_Bm_ACCHs) /*|| ch_ts > 4*/ || ch_subch >= 4) {
- printf("Channel type %d, subch %d, ts %d not supported, "
- "exitting.\n", ch_type, ch_subch, ch_ts);
- exit(-ENOTSUP);
- }
- if (rr->cd_now.h)
- l1ctl_tx_dm_est_req_h1(ms, rr->cd_now.maio, rr->cd_now.hsn,
- ma, ma_len, rr->cd_now.chan_nr, rr->cd_now.tsc);
- else
- l1ctl_tx_dm_est_req_h0(ms, rr->cd_now.arfcn, rr->cd_now.chan_nr,
- rr->cd_now.tsc);
-#endif
+ gsm48_rr_activate_channel(ms, &rr->cd_now, ma, ma_len);
/* start establishmnet */
return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
@@ -3022,6 +3145,8 @@ static int gsm48_rr_rx_chan_modify(struct osmocom_ms *ms, struct msgb *msg)
default:
LOGP(DRR, LOGL_ERROR, "Mode %u not supported!\n", mode);
}
+ rr->cd_now.mode = mode;
+#warning FIXME: set mode
return gsm48_rr_tx_chan_modify_ack(ms, &cm->chan_desc, mode);
}
@@ -3077,16 +3202,26 @@ static int gsm48_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause)
/* 9.1.2 ASSIGNMENT COMMAND is received */
static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
{
-// struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm48_hdr *gh = msgb_l3(msg);
struct gsm48_ass_cmd *ac = (struct gsm48_ass_cmd *)gh->data;
int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*ac);
struct tlv_parsed tp;
- struct gsm48_rr_cd cd;
+ struct gsm48_rr_cd *cda = &rr->cd_after;
+ struct gsm48_rr_cd *cdb = &rr->cd_before;
+ 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, "ASSIGNMENT COMMAND\n");
- memset(&cd, 0, sizeof(cd));
+ memset(cda, 0, sizeof(*cda));
+ memset(cdb, 0, sizeof(*cdb));
if (payload_len < 0) {
LOGP(DRR, LOGL_NOTICE, "Short read of ASSIGNMENT COMMAND "
@@ -3096,73 +3231,352 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
}
tlv_parse(&tp, &gsm48_rr_att_tlvdef, ac->data, payload_len, 0, 0);
-#if 0
- /* channel description */
- memcpy(&cd.chan_desc, &ac->chan_desc, sizeof(chan_desc));
- /* power command */
- cd.power_command = ac->power_command;
- /* frequency list, after timer */
- tlv_copy(&cd.fl, sizeof(fl_after), &tp, GSM48_IE_FRQLIST_AFTER);
+ /* 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 = ac->chan_desc.chan_nr;
+ rsl_dec_chan_nr(cda->chan_nr, &ch_type, &ch_subch, &ch_ts);
+ if (ac->chan_desc.h0.h) {
+ cda->h = 1;
+ gsm48_decode_chan_h1(&ac->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", ac->chan_desc.chan_nr,
+ cda->maio, cda->hsn, ch_ts, ch_subch, cda->tsc);
+ } else {
+ cda->h = 0;
+ gsm48_decode_chan_h0(&ac->chan_desc, &cda->tsc, &cda->arfcn);
+ LOGP(DRR, LOGL_INFO, " after: (chan_nr 0x%02x ARFCN %u TS %u "
+ "SS %u TSC %u)\n", ac->chan_desc.chan_nr,
+ cda->arfcn, ch_ts, ch_subch, cda->tsc);
+ }
+
+ /* starting time */
+ 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;
+ } 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");
+ }
+ }
+
+ /* 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 */
- tlv_copy(&cd.ccd, sizeof(ccd), &tp, GSM48_IE_CELL_CH_DESC);
- /* multislot allocation */
- tlv_copy(&cd.multia, sizeof(ma), &tp, GSM48_IE_MSLOT_DESC);
+ 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 */
- tlv_copy(&cd.chanmode, sizeof(chanmode), &tp, GSM48_IE_CHANMODE_1);
- /* mobile allocation, after time */
- tlv_copy(&cd.moba_after, sizeof(moba_after), &tp, GSM48_IE_MOB_AL_AFTER);
- /* starting time */
- tlv_copy(&cd.start, sizeof(start), &tp, GSM_IE_START_TIME);
- /* frequency list, before time */
- tlv_copy(&cd.fl_before, sizeof(fl_before), &tp, GSM48_IE_FRQLIST_BEFORE);
- /* channel description, before time */
- tlv_copy(&cd.chan_desc_before, sizeof(cd_before), &tp, GSM48_IE_CHDES_1_BEFORE);
- /* frequency channel sequence, before time */
- tlv_copy(&cd.fcs_before, sizeof(fcs_before), &tp, GSM48_IE_FRQSEQ_BEFORE);
- /* mobile allocation, before time */
- tlv_copy(&cd.moba_before, sizeof(moba_before), &tp, GSM48_IE_MOB_AL_BEFORE);
+ 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))
- cd.cipher = *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET);
- else
- cd.cipher = 0;
+ 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 *) &ac->power_command,
+ &cda->ind_tx_power, NULL);
+ 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)\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;
+
+ /* 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");
+ before_time = 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;
+ }
+ }
+ }
- if (no CA) {
- LOGP(DRR, LOGL_INFO, "No current cell allocation available.\n");
- return gsm48_rr_tx_ass_fail(ms, GSM48_GSM48_RR_CAUSE_NO_CELL_ALLOC_A);
+ /* check if channels are valid */
+ if (before_time) {
+ cause = gsm48_rr_render_ma(ms, cdb, ma, &ma_len);
+ if (cause)
+ return gsm48_rr_tx_ass_fail(ms, cause);
}
-
+ 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_INFO, "New channel is not supported.\n");
- return gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_CHAN_MODE_UNACCEPT);
+ LOGP(DRR, LOGL_NOTICE, "New channel is not supported.\n");
+ return GSM48_RR_CAUSE_CHAN_MODE_UNACCEPT;
}
+#endif
- if (freq not supported) {
- LOGP(DRR, LOGL_INFO, "New frequency is not supported.\n");
- return gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_FREQ_NOT_IMPL);
+ /* schedule start of assignment */
+ if (before_time) {
+ LOGP(DRR, LOGL_INFO, "FIXME starting time not supported yet\n");
+ return -ENOTSUP;
}
- /* store current channel descriptions, to return in case of failure */
- memcpy(&rr->chan_last, &rr->chan_desc, sizeof(*cd));
- /* copy new description */
- memcpy(&rr->chan_desc, cd, sizeof(cd));
-
/* start suspension of current link */
+ 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, msg);
+ 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;
-#else
- return gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_FREQ_NOT_IMPL);
-#endif
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;
+
+ if (rr->hando_susp_state || rr->assign_susp_state) {
+ LOGP(DRR, LOGL_INFO, "data link is resumed\n");
+
+ 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);
+ }
+
+ 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->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");
+
+ /* deactivating dedicated mode */
+ LOGP(DRR, LOGL_INFO, "leaving dedicated mode\n");
+ l1ctl_tx_dm_rel_req(rr->ms);
+
+ /* 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));
+
+ /* 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);
+
+ /* 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->hando_susp_state) {
+ gsm48_rr_tx_hando_access(ms);
+ rr->hando_acc_left = 3;
+ }
+#endif
+ }
+ return 0;
+}
+
/*
* radio ressource requests
*/
@@ -3270,20 +3684,6 @@ static int gsm48_rr_est_req(struct osmocom_ms *ms, struct msgb *msg)
return gsm48_rr_chan_req(ms, rrh->cause, 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;
-}
-
/* 3.4.2 transfer data in dedicated mode */
static int gsm48_rr_data_req(struct osmocom_ms *ms, struct msgb *msg)
{
@@ -3337,11 +3737,9 @@ static int gsm48_rr_data_ind(struct osmocom_ms *ms, struct msgb *msg)
case GSM48_MT_RR_ASS_CMD:
rc = gsm48_rr_rx_ass_cmd(ms, msg);
break;
-#if 0
- case GSM48_MT_RR_CIP_MODE_CMD:
+ case GSM48_MT_RR_CIPH_M_CMD:
rc = gsm48_rr_rx_cip_mode_cmd(ms, msg);
break;
-#endif
case GSM48_MT_RR_CLSM_ENQ:
rc = gsm48_rr_rx_cm_enq(ms, msg);
break;
@@ -3457,13 +3855,14 @@ static int gsm48_rr_rx_acch(struct osmocom_ms *ms, struct msgb *msg)
ind_ta, ind_ta - set->alter_delay);
LOGP(DRR, LOGL_INFO, "Indicated tx_power %d\n",
ind_tx_power);
- if (ind_ta != rr->ind_ta || ind_tx_power != rr->ind_tx_power) {
+ if (ind_ta != rr->cd_now.ind_ta
+ || ind_tx_power != rr->cd_now.ind_tx_power) {
LOGP(DRR, LOGL_INFO, "setting new ta and tx_power\n");
l1ctl_tx_param_req(ms, ind_ta - set->alter_delay,
(set->alter_tx_power) ? set->alter_tx_power_value
: ind_tx_power);
- rr->ind_ta = ind_ta;
- rr->ind_tx_power = ind_tx_power;
+ rr->cd_now.ind_ta = ind_ta;
+ rr->cd_now.ind_tx_power = ind_tx_power;
}
switch (sih->system_information) {
@@ -3596,35 +3995,6 @@ static int gsm48_rr_abort_req(struct osmocom_ms *ms, struct msgb *msg)
return 0;
}
-/* release 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->hando_susp_state || rr->assign_susp_state) {
- struct msgb *nmsg;
-
- /* change radio to new channel */
-//todo tx_ph_dm_est_req(ms, rr->cd_now.arfcn, rr->cd_now.chan_nr,
-// rr->cd_now.tsc);
-
- /* send DL-ESTABLISH REQUEST */
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
-
-#ifdef TODO
- /* trigger RACH */
- if (rr->hando_susp_state) {
- gsm48_rr_tx_hando_access(ms);
- rr->hando_acc_left = 3;
- }
-#endif
- }
- return 0;
-}
-
/* release confirm */
static int gsm48_rr_rel_cnf(struct osmocom_ms *ms, struct msgb *msg)
{
@@ -3676,15 +4046,10 @@ static struct dldatastate {
SBIT(GSM48_RR_ST_REL_PEND),
RSL_MT_EST_CONF, gsm48_rr_estab_cnf},
-#if 0
+ /* resume */
{SBIT(GSM48_RR_ST_DEDICATED),
RSL_MT_EST_CONF, gsm48_rr_estab_cnf_dedicated},
- {SBIT(GSM_RRSTATE),
- RSL_MT_CONNECT_CNF, gsm48_rr_connect_cnf},
-
-#endif
-
/* release */
{SBIT(GSM48_RR_ST_CONN_PEND) |
SBIT(GSM48_RR_ST_DEDICATED),
@@ -3901,67 +4266,8 @@ int gsm48_rr_exit(struct osmocom_ms *ms)
#if 0
-the process above is complete
-------------------------------------------------------------------------------
-incomplete
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-todo:
-
-stop timers on abort
-wird beim abbruch immer der gepufferte cm-service-request entfernt, auch beim verschicken?:
-measurement reports
todo rr_sync_ind when receiving ciph, re ass, channel mode modify
-todo change procedures, release procedure
-
-static int gsm48_rr_act_req(struct osmocom_ms *ms, struct gsm48_rr *rrmsg)
-{
-}
-
-
-}
-
-/* memcopy of LV of given IE from tlv_parsed structure */
-static int tlv_copy(void *dest, int dest_len, struct tlv_parsed *tp, uint8_t ie)
-{
- uint8_t *lv = dest;
- uint8_t len;
-
- if (dest_len < 1)
- return -EINVAL;
- lv[0] = 0;
-
- if (!TLVP_PRESENT(tp, ie))
- return 0;
-
- len = TLVP_LEN(tp, ie);
- if (len < 1)
- return 0;
- if (len + 1 > dest_len)
- return -ENOMEM;
-
- memcpy(dest, TLVP_VAL(tp, ie) - 1, len + 1);
- 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)
@@ -3971,16 +4277,8 @@ static int gsm48_decode_cell_desc(struct gsm48_cell_desc *cd, uint16_t *arfcn, u
*bcc = cd->bcc;
}
-/* decode "Power Command" (10.5.2.28) and (10.5.2.28a) */
-static int gsm48_decode_power_cmd_acc(struct gsm48_power_cmd *pc, uint8_t *power_level uint8_t *atc)
-{
- *power_level = pc->power_level;
- if (atc) /* only in case of 10.5.2.28a */
- *atc = pc->atc;
-}
-
/* decode "Synchronization Indication" (10.5.2.39) */
-static int gsm48_decode_power_cmd_acc(struct gsm48_rrlayer *rr, struct gsm48_rr_sync_ind *si)
+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;
@@ -4006,39 +4304,13 @@ static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
}
tlv_parse(&tp, &gsm48_rr_att_tlvdef, ho->data, payload_len, 0, 0);
- /* decode Cell Description */
- gsm_decode_cell_desc(&ho->cell_desc, &cd.bcch_arfcn, &cd.ncc, &cd.bcc);
- /* Channel Description */
- memcpy(&rr->chan_desc.chan_desc, ho->chan_desc, 3);
- /* Handover Reference */
- rr->hando_ref = ho->ho_ref;
- /* Power Command and access type */
- gsm_decode_power_cmd_acc((struct gsm48_power_cmd *)&ho->power_command,
- &cd.power_level, cd.atc);
- /* Synchronization Indication */
- if (TLVP_PRESENT(&tp, GSM48_IE_SYNC_IND))
- gsm48_decode_sync_ind(rr,
- TLVP_VAL(&tp, GSM48_IE_SYNC_IND)-1, &cd);
- /* Frequency Sort List */
- if (TLVP_PRESENT(&tp, GSM48_IE_FREQ_SHORT_LIST))
- decode_freq_list(&ms->support, s->freq,
- TLVP_VAL(&tp, GSM48_IE_FREQ_SHORT_LIST),
- *(TLVP_VAL(&tp, GSM48_IE_FREQ_SHORT_LIST)-1),
- 0xce, FREQ_TYPE_SERV);
-
-
-today: more IE parsing
-
- /* store current channel descriptions, to return in case of failure */
- memcpy(&rr->chan_last, &rr->chan_desc, sizeof(*cd));
- /* copy new description */
- memcpy(&rr->chan_desc, cd, sizeof(cd));
+TODO
/* start suspension of current link */
nmsg = gsm48_l3_msgb_alloc();
if (!nmsg)
return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, msg);
+ gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg);
/* change into special handover suspension state */
rr->hando_susp_state = 1;
@@ -4047,26 +4319,6 @@ today: more IE parsing
return 0;
}
-static int gsm48_rr_estab_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
-{
- if (rr->hando_susp_state || rr->assign_susp_state) {
- if (rr->resume_last_state) {
- rr->resume_last_state = 0;
- gsm48_rr_tx_ass_cpl(ms, GSM48_RR_CAUSE_NORMAL);
- } else {
- gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_PROTO_ERR_UNSPEC);
- }
- /* transmit queued frames during ho / ass transition */
- gsm48_rr_dequeue_down(ms);
- }
-
- return 0;
-}
-
-static int gsm48_rr_connect_cnf(struct osmocom_ms *ms, struct msgbl *msg)
-{
-}
-
static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_rrlayer *rr = ms->rrlayer;
@@ -4085,14 +4337,17 @@ static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
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->chan_desc, &rr->chan_last, sizeof(*cd));
+ memcpy(&rr->cd_now, &rr->chan_last, sizeof(rr->cd_now));
- /* change radio to old channel */
- tx_ph_dm_est_req(ms, rr->cd_now.arfcn,
- rr->cd_now.chan_nr, rr->cd_now.tsc);
+ /* 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();