summaryrefslogtreecommitdiffstats
path: root/src/host/gsm48-andreas
diff options
context:
space:
mode:
authorAndreas Eversberg2010-03-14 18:08:16 +0100
committerAndreas Eversberg2010-03-14 18:08:16 +0100
commitcb46d4a071c8b572bee18a55dd241c34ab502764 (patch)
treebe7df4bb58725409defcf98af9d3a8e3bc167e0d /src/host/gsm48-andreas
parentMerge branch 'master' of gitosis@git.osmocom.org:osmocom-bb (diff)
downloadosmocom-cb46d4a071c8b572bee18a55dd241c34ab502764.tar.gz
osmocom-cb46d4a071c8b572bee18a55dd241c34ab502764.tar.xz
osmocom-cb46d4a071c8b572bee18a55dd241c34ab502764.zip
Work on Radio Ressource layer.
- SI 1-4 parsing - decoding of all frequency list types
Diffstat (limited to 'src/host/gsm48-andreas')
-rw-r--r--src/host/gsm48-andreas/extra.h190
-rw-r--r--src/host/gsm48-andreas/gsm48_l3.h27
-rw-r--r--src/host/gsm48-andreas/gsm48_rr.c905
-rw-r--r--src/host/gsm48-andreas/support.c6
-rw-r--r--src/host/gsm48-andreas/sysinfo.c30
-rw-r--r--src/host/gsm48-andreas/sysinfo.h56
6 files changed, 1152 insertions, 62 deletions
diff --git a/src/host/gsm48-andreas/extra.h b/src/host/gsm48-andreas/extra.h
index 55ce975..1146753 100644
--- a/src/host/gsm48-andreas/extra.h
+++ b/src/host/gsm48-andreas/extra.h
@@ -33,6 +33,170 @@ struct gsm48_classmark2 {
cm3:1;
} __attribute__ ((packed));
+/* 10.5.2.1b.3 */
+struct gsm48_range_1024 {
+ uint8_t w1_hi:2,
+ f0:1,
+ form_id:5;
+ uint8_t w1_lo;
+ uint8_t w2_hi;
+ uint8_t w3_hi:7,
+ w2_lo:1;
+ uint8_t w4_hi:6,
+ w3_lo:2;
+ uint8_t w5_hi:6,
+ w4_lo:2;
+ uint8_t w6_hi:6,
+ w5_lo:2;
+ uint8_t w7_hi:6,
+ w6_lo:2;
+ uint8_t w8_hi:6,
+ w7_lo:2;
+ uint8_t w9:7,
+ w8_lo:1;
+ uint8_t w11_hi:1,
+ w10:7;
+ uint8_t w12_hi:2,
+ w11_lo:6;
+ uint8_t w13_hi:3,
+ w12_lo:5;
+ uint8_t w14_hi:4,
+ w13_lo:4;
+ uint8_t w15_hi:5,
+ w14_lo:3;
+ uint8_t w16:6,
+ w15_lo:2;
+} __attribute__ ((packed));
+
+/* 10.5.2.1b.4 */
+struct gsm48_range_512 {
+ uint8_t orig_arfcn_hi:1,
+ form_id:7;
+ uint8_t orig_arfcn_mid;
+ uint8_t w1_hi:7,
+ orig_arfcn_lo:1;
+ uint8_t w2_hi:6,
+ w1_lo:2;
+ uint8_t w3_hi:6,
+ w2_lo:2;
+ uint8_t w4_hi:6,
+ w3_lo:2;
+ uint8_t w5:7,
+ w4_lo:1;
+ uint8_t w7_hi:1,
+ w6:7;
+ uint8_t w8_hi:2,
+ w7_lo:6;
+ uint8_t w9_hi:4,
+ w8_lo:4;
+ uint8_t w10:6,
+ w9_lo:2;
+ uint8_t w12_hi:2,
+ w11:6;
+ uint8_t w13_hi:4,
+ w12_lo:4;
+ uint8_t w14:6,
+ w13_lo:2;
+ uint8_t w16_hi:2,
+ w15:6;
+ uint8_t w17:5,
+ w16_lo:3;
+} __attribute__ ((packed));
+
+/* 10.5.2.1b.5 */
+struct gsm48_range_256 {
+ uint8_t orig_arfcn_hi:1,
+ form_id:7;
+ uint8_t orig_arfcn_mid;
+ uint8_t w1_hi:7,
+ orig_arfcn_lo:1;
+ uint8_t w2:7,
+ w1_lo:1;
+ uint8_t w4_hi:1,
+ w3:7;
+ uint8_t w5_hi:3,
+ w4_lo:5;
+ uint8_t w6_hi:5,
+ w5_lo:3;
+ uint8_t w8_hi:1,
+ w7:6,
+ w6_lo:1;
+ uint8_t w9_hi:4,
+ w8_lo:4;
+ uint8_t w11_hi:2,
+ w10:5;
+ w9_lo:1;
+ uint8_t w12:5,
+ w11_lo:3;
+ uint8_t w14_hi:3,
+ w13:5;
+ uint8_t w16_hi:1,
+ w15:5,
+ w14_lo:2;
+ uint8_t w18_hi:1,
+ w17:4,
+ w16_lo:3;
+ uint8_t w20_hi:1,
+ w19:4,
+ w18_lo:3;
+ uint8_t spare:1,
+ w21:4,
+ w20_lo:3;
+} __attribute__ ((packed));
+
+/* 10.5.2.1b.6 */
+struct gsm48_range_128 {
+ uint8_t orig_arfcn_hi:1,
+ form_id:7;
+ uint8_t orig_arfcn_mid;
+ uint8_t w1:7,
+ orig_arfcn_lo:1;
+ uint8_t w3_hi:2,
+ w2:6;
+ uint8_t w4_hi:4,
+ w3_lo:4;
+ uint8_t w6_hi:2,
+ w5:5,
+ w4_lo:1;
+ uint8_t w7:5,
+ w6_lo:3;
+ uint8_t w9:4,
+ w8:4;
+ uint8_t w11:4,
+ w10:4;
+ uint8_t w13:4,
+ w12:4;
+ uint8_t w15:4,
+ w14:4;
+ uint8_t w18_hi:2,
+ w17:3,
+ w16:3;
+ uint8_t w21_hi:1,
+ w20:3,
+ w19:3,
+ w18_lo:1;
+ uint8_t w23:3,
+ w22:3,
+ w21_lo:2;
+ uint8_t w26_hi:2,
+ w25:3,
+ w24:3;
+ uint8_t spare:1,
+ w28:3,
+ w27:3,
+ w26_lo:1;
+} __attribute__ ((packed));
+
+/* 10.5.2.1b.7 */
+struct gsm48_var_bit {
+ uint8_t orig_arfcn_hi:1,
+ form_id:7;
+ uint8_t orig_arfcn_mid;
+ uint8_t rrfcn1_7:7,
+ orig_arfcn_lo:1;
+ uint8_t rrfcn8_111[13];
+} __attribute__ ((packed));
+
/* 10.5.2.20 */
struct gsm48_meas_res {
uint8_t rxlev_full:6,
@@ -74,6 +238,15 @@ struct gsm48_meas_res {
rxlev_nc6_lo:5;
uint8_t bsic_nc6:6,
bcch_f_nc6_lo:2;
+} __attribute__ ((packed));
+
+/* 10.5.2.29 */
+struct gsm48_rach_ctl {
+ uint8_t re:1,
+ cell_barr:1,
+ tx_int:4,
+ max_retr:2;
+ uint8_t ac[2];
} __attribute__((packed));
/* Chapter 9.1.1 */
@@ -217,6 +390,23 @@ struct gsm48_rr_status {
uint8_t rr_cause;
} __attribute__((packed));
+/* Section 9.1.33 System information Type 2bis */
+struct gsm48_system_information_type_2bis {
+ struct gsm48_system_information_type_header header;
+ uint8_t bcch_frequency_list[16];
+ struct gsm48_rach_control rach_control;
+ uint8_t rest_octets[0];
+} __attribute__ ((packed));
+
+/* Section 9.1.34 System information Type 2ter */
+struct gsm48_system_information_type_2ter {
+ struct gsm48_system_information_type_header header;
+ uint8_t ext_bcch_frequency_list[16];
+ uint8_t rest_octets[0];
+} __attribute__ ((packed));
+
+
+
rsl.h:
/* encode channel number and frequency as per Section 9.3.1 */
diff --git a/src/host/gsm48-andreas/gsm48_l3.h b/src/host/gsm48-andreas/gsm48_l3.h
index c4553c8..7e77eef 100644
--- a/src/host/gsm48-andreas/gsm48_l3.h
+++ b/src/host/gsm48-andreas/gsm48_l3.h
@@ -252,21 +252,44 @@ struct gsm_mmlayer {
/* GSM 04.08 RR timers */
#define GSM_T3126_MS 5, 0
+struct gsm_rr_chan_desc {
+ struct gsm48_chan_desc chan_desc;
+ uint8_t power_command;
+ uint8_t frq_list_before[131];
+ uint8_t frq_list_after[131];
+ uint8_t cell_chan_desc[16];
+ uint8_t ...
+ uint8_t
+ uint8_t
+};
+
/* RR sublayer instance */
struct gsm_rrlayer {
struct osmocom_ms *ms;
int state;
+ struct timer_list t3122;
+ struct timer_list t3124;
struct timer_list t3126;
int t3126_value;
+
+ /* states if RR-EST-REQ was used */
int rr_est_req;
- struct gsm_msgb *rr_est_msg;
+ struct msgb *rr_est_msg;
+ /* channel request states */
u_int8_t chan_req;
/* cr_hist must be signed and greater 8 bit */
int cr_hist[3];
- uint8_t sc, alg_id;
+ /* collection of all channel descriptions */
+ struct gsm_rr_chan_desc chan_desc;
+
+ /* special states when changing channel */
+ int hando_susp_state;
+ int assign_susp_state;
+ int resume_last_state;
+ struct gsm_rr_chan_desc chan_last;
};
diff --git a/src/host/gsm48-andreas/gsm48_rr.c b/src/host/gsm48-andreas/gsm48_rr.c
index ada8161..ebac35c 100644
--- a/src/host/gsm48-andreas/gsm48_rr.c
+++ b/src/host/gsm48-andreas/gsm48_rr.c
@@ -35,11 +35,17 @@ static void new_rr_state(struct gsm_rrlayer *rr, int state)
return;
if (state == GSM_RRSTATE_IDLE) {
+ struct msgb *msg;
+
+ /* free establish message, if any */
rr->rr_est_req = 0;
if (rr->rr_est_msg) {
msgb_free(rr->rr_est_msg);
rr->rr_est_msg = NULL;
}
+ /* free all pending messages */
+ while((msg = msgb_dequeue(&rr->downqueue)))
+ free_msgb(msg);
}
DEBUGP(DRR, "new state %s -> %s\n",
@@ -175,7 +181,7 @@ static int gsm_rr_rx_cip_mode_cmd(struct osmocom_ms *ms, struct msgb *msg)
if (payload_len < 0) {
DEBUGP(DRR, "Short read of CIPHERING MODE COMMAND message.\n");
- return -EINVAL;
+ return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
}
/* cipher mode setting */
@@ -877,7 +883,8 @@ static int gsm_rr_rx_imm_ass(struct osmocom_ms *ms, struct gsm_msgb *msg)
/* request ref */
if (gsm_match_ra(ms, ia->req_ref)) {
/* channel description */
- memcpy(rr->chan_desc, ia->chan_desc, 3);
+ memset(&rr->chan_desc, 0, sizeof(cd));
+ memcpy(rr->chan_desc.chan_desc, ia->chan_desc, 3);
/* timing advance */
rr->timing_advance = ia->timing_advance;
/* mobile allocation */
@@ -913,7 +920,8 @@ static int gsm_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct gsm_msgb *msg)
/* request ref 1 */
if (gsm_match_ra(ms, ia->req_ref1)) {
/* channel description */
- memcpy(rr->chan_desc, ia->chan_desc1, 3);
+ memset(&rr->chan_desc, 0, sizeof(cd));
+ memcpy(rr->chan_desc.chan_desc, ia->chan_desc1, 3);
/* timing advance */
rr->timing_advance = ia->timing_advance1;
/* mobile allocation */
@@ -924,7 +932,8 @@ static int gsm_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct gsm_msgb *msg)
/* request ref 1 */
if (gsm_match_ra(ms, ia->req_ref2)) {
/* channel description */
- memcpy(rr->chan_desc, ia->chan_desc2, 3);
+ memset(&rr->chan_desc, 0, sizeof(cd));
+ memcpy(rr->chan_desc.chan_desc, ia->chan_desc2, 3);
/* timing advance */
rr->timing_advance = ia->timing_advance2;
/* mobile allocation */
@@ -989,7 +998,7 @@ static int gsm_rr_rx_add_ass(struct osmocom_ms *ms, struct msgb *msg)
if (payload_len < 0) {
DEBUGP(DRR, "Short read of ADDITIONAL ASSIGNMENT message.\n");
- return -EINVAL;
+ return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
}
tlv_parse(&tp, &rsl_att_tlvdef, aa->data, payload_len, 0, 0);
@@ -1123,10 +1132,10 @@ static int gsm_rr_dl_est(struct osmocom_ms *ms)
}
/* activate channel */
- tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_nr);
+ tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
/* start establishmnet */
- return rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_nr, 0, msg);
+ return rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_desc.chan_nr, 0, msg);
}
/* the link is established */
@@ -1161,7 +1170,7 @@ static int gsm_rr_estab_cnf(struct osmocom_ms *ms, struct msgb *msg)
static int gsm_rr_rel_cnf(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
{
/* deactivate channel */
- tx_ph_dm_rel_req(ms, arfcn, rr->chan_desc.chan_nr);
+ tx_ph_dm_rel_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
/* do nothing, because we aleady IDLE
* or we received the rel cnf of the last connection
@@ -1240,10 +1249,23 @@ static int gsm_rr_est_req(struct osmocom_ms *ms, struct msgb *msg)
return gsm_rr_tx_chan_req(ms, mmh->cause);
}
+/* send all queued messages down to layer 2 */
+static int gsm_rr_dequeue_down(struct osmocom_ms *ms)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct msgb *msg;
+
+ while((msg = msgb_dequeue(&rr->downqueue))) {
+ rslms_tx_rll_req_l3(ms, RSL_MT_DATA_REQ, chan_nr, 0, msg);
+ }
+
+ return 0;
+}
+
/* 3.4.2 transfer data in dedicated mode */
static int gsm_rr_data_req(struct osmocom_ms *ms, struct msgb *msg)
{
- struct gsm_dl dlmsg;
+ struct gsm_rrlayer *rr = ms->rrlayer;
if (rr->state != GSM_RRSTATE_DEDICATED) {
msgb_free(msg)
@@ -1252,6 +1274,13 @@ static int gsm_rr_data_req(struct osmocom_ms *ms, struct msgb *msg)
/* pull header */
msgb_pull(msg, sizeof(struct gsm_mm_hdr));
+
+ /* queue message, during handover or assignment procedure */
+ if (rr->hando_susp_state || rr->assign_susp_state) {
+ msgb_enqueue(&rr->downqueue, msg);
+ return 0;
+ }
+
/* forward message */
return rslms_tx_rll_req_l3(ms, RSL_MT_DATA_REQ, chan_nr, 0, msg);
}
@@ -1336,6 +1365,711 @@ uncomplete
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ * system information
+ */
+
+/* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */
+static int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd, uint8_t len, uint8_t mask)
+{
+ int i;
+
+ /* NOTES:
+ *
+ * The Range format uses "SMOD" computation.
+ * e.g. "n SMOD m" equals "((n - 1) % m) + 1"
+ * A cascade of multiple SMOD computations is simpified:
+ * "(n SMOD m) SMOD o" equals "(((n - 1) % m) % o) + 1"
+ *
+ * The Range format uses 16 octets of data in SYSTEM INFORMATION.
+ * When used in dedicated messages, the length can be less.
+ * In this case the ranges are decoded for all frequencies that
+ * fit in the block of given length.
+ */
+
+ /* tabula rasa */
+ for (i = 0; i < 1024; i++)
+ f[i].used = 0;
+
+ /* 00..XXX. */
+ if ((cd[0] & 0xc0 & mask) == 0x00) {
+ /* Bit map 0 format */
+ if (len < 16)
+ return -EINVAL;
+ for (i = 1; i <= 124; i++)
+ if ((cd[15 - ((i-1) >> 3)] & (1 << ((i-1) & 7))))
+ f[i].used = 1;
+
+ return 0;
+ }
+
+ /* only Bit map 0 format for P-GSM */
+ if (ms->support.p_gsm && !ms->support.e_gsm
+ && !ms->support.r_gsm && !ms->support.dcs_1800)
+ return 0;
+
+ /* 10..0XX. */
+ if ((cd[0] & 0xc8 & mask) == 0x80) {
+ /* Range 1024 format */
+ uint16_t w[17]; /* 1..16 */
+ struct gsm_range_1024 *r = (struct gsm_range_1024 *)cd;
+
+ if (len < 2)
+ return -EINVAL;
+ memset(w, 0, sizeof(w));
+ if (r->f0)
+ f[0].used = 1;
+ w[1] = (r->w1_hi << 8) | r->w1_lo;
+ if (len >= 4)
+ w[2] = (r->w2_hi << 1) | r->w2_lo;
+ if (len >= 5)
+ w[3] = (r->w3_hi << 2) | r->w3_lo;
+ if (len >= 6)
+ w[4] = (r->w4_hi << 2) | r->w4_lo;
+ if (len >= 7)
+ w[5] = (r->w5_hi << 2) | r->w5_lo;
+ if (len >= 8)
+ w[6] = (r->w6_hi << 2) | r->w6_lo;
+ if (len >= 9)
+ w[7] = (r->w7_hi << 2) | r->w7_lo;
+ if (len >= 10)
+ w[8] = (r->w8_hi << 1) | r->w8_lo;
+ if (len >= 10)
+ w[9] = r->w9;
+ if (len >= 11)
+ w[10] = r->w10;
+ if (len >= 12)
+ w[11] = (r->w11_hi << 6) | r->w11_lo;
+ if (len >= 13)
+ w[12] = (r->w12_hi << 5) | r->w12_lo;
+ if (len >= 14)
+ w[13] = (r->w13_hi << 4) | r->w13_lo;
+ if (len >= 15)
+ w[14] = (r->w14_hi << 3) | r->w14_lo;
+ if (len >= 16)
+ w[15] = (r->w15_hi << 2) | r->w15_lo;
+ if (len >= 16)
+ w[16] = r->w16;
+ if (w[1])
+ f[w[1]].used = 1;
+ if (w[2])
+ f[((w[1] - 512 + w[2] - 1) % 1023) + 1].used = 1;
+ if (w[3])
+ f[((w[1] + w[3] - 1) % 1023) + 1].used = 1;
+ if (w[4])
+ f[((w[1] - 512 + ((w[2] - 256 + w[4] - 1) % 511)) % 1023) + 1].used = 1;
+ if (w[5])
+ f[((w[1] + ((w[3] - 256 - w[5] - 1) % 511)) % 1023) + 1].used = 1;
+ if (w[6])
+ f[((w[1] - 512 + ((w[2] + w[6] - 1) % 511)) % 1023) + 1].used = 1;
+ if (w[7])
+ f[((w[1] + ((w[3] + w[7] - 1) % 511)) % 1023) + 1].used = 1;
+ if (w[8])
+ f[((w[1] - 512 + ((w[2] - 256 + ((w[4] - 128 + w[8] - 1) % 255)) % 511)) % 1023) + 1].used = 1;
+ if (w[9])
+ f[((w[1] + ((w[3] - 256 + ((w[5] - 128 + w[9] - 1) % 255)) % 511)) % 1023) + 1].used = 1;
+ if (w[10])
+ f[((w[1] - 512 + ((w[2] + ((w[6] - 128 + w[10] - 1) % 255)) % 511)) % 1023) + 1].used = 1;
+ if (w[11])
+ f[((w[1] + ((w[3] + ((w[7] - 128 + w[11] - 1) % 255)) % 511)) % 1023) + 1].used = 1;
+ if (w[12])
+ f[((w[1] - 512 + ((w[2] - 256 + ((w[4] + w[12] - 1) % 255)) % 511)) % 1023) + 1].used = 1;
+ if (w[13])
+ f[((w[1] + ((w[3] - 256 + ((w[5] + w[13] - 1) % 255)) % 511)) % 1023) + 1].used = 1;
+ if (w[14])
+ f[((w[1] - 512 + ((w[2] + ((w[6] + w[14] - 1) % 255)) % 511)) % 1023) + 1].used = 1;
+ if (w[15])
+ f[((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 255)) % 511)) % 1023) + 1].used = 1;
+ if (w[16])
+ f[((w[1] - 512 + ((w[2] - 256 + ((w[4] - 128 + ((w[8] - 64 + w[16] - 1) % 127)) % 255)) % 511)) % 1023) + 1].used = 1;
+
+ return 0;
+ }
+ /* 10..100. */
+ if ((cd[0] & 0xce & mask) == 0x88) {
+ /* Range 512 format */
+ uint16_t w[18]; /* 1..17 */
+ struct gsm_range_512 *r = (struct gsm_range_512 *)cd;
+
+ if (len < 4)
+ return -EINVAL;
+ memset(w, 0, sizeof(w));
+ w[0] = (r->orig_arfcn_hi << 9) || (r->orig_arfcn_mid << 1) || r->orig_arfcn_lo;
+ w[1] = (r->w1_hi << 2) || r->w1_lo;
+ if (len >= 5)
+ w[2] = (r->w2_hi << 2) || r->w2_lo;
+ if (len >= 6)
+ w[3] = (r->w3_hi << 2) || r->w3_lo;
+ if (len >= 7)
+ w[4] = (r->w4_hi << 1) || r->w4_lo;
+ if (len >= 7)
+ w[5] = r->w5;
+ if (len >= 8)
+ w[6] = r->w6;
+ if (len >= 9)
+ w[7] = (r->w7_hi << 6) || r->w7_lo;
+ if (len >= 10)
+ w[8] = (r->w8_hi << 4) || r->w8_lo;
+ if (len >= 11)
+ w[9] = (r->w9_hi << 2) || r->w9_lo;
+ if (len >= 11)
+ w[10] = r->w10;
+ if (len >= 12)
+ w[11] = r->w11;
+ if (len >= 13)
+ w[12] = (r->w12_hi << 4) || r->w12_lo;
+ if (len >= 14)
+ w[13] = (r->w13_hi << 2) || r->w13_lo;
+ if (len >= 14)
+ w[14] = r->w14;
+ if (len >= 15)
+ w[15] = r->w15;
+ if (len >= 16)
+ w[16] = (r->w16_hi << 3) || r->w16_lo;
+ if (len >= 16)
+ w[17] = r->w17;
+ if (w[0])
+ f[w[0]].used = 1;
+ if (w[1])
+ f[(w[0] + w[1]) % 1024].used = 1;
+ if (w[2])
+ f[(w[0] + ((w[1] - 256 + w[2] - 1) % 511) + 1) % 1024].used = 1;
+ if (w[3])
+ f[(w[0] + ((w[1] + w[3] - 1) % 511) + 1) % 1024].used = 1;
+ if (w[4])
+ f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + w[4] - 1) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[5])
+ f[(w[0] + ((w[1] + ((w[3] - 128 + w[5] - 1) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[6])
+ f[(w[0] + ((w[1] - 256 + ((w[2] + w[6] - 1) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[7])
+ f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[8])
+ f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] - 64 + w[8] - 1) % 127)) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[9])
+ f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] - 64 + w[9] - 1) % 127)) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[10])
+ f[(w[0] + ((w[1] - 256 + ((w[2] + ((w[6] - 64 + w[10] - 1) % 127)) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[11])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 64 + w[11] - 1) % 127)) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[12])
+ f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] + w[12] - 1) % 127)) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[13])
+ f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] + w[13] - 1) % 127)) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[14])
+ f[(w[0] + ((w[1] - 256 + ((w[2] + ((w[6] + w[14] - 1) % 127)) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[15])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 127)) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[16])
+ f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] - 64 + ((w[8] - 32 + w[16] - 1) % 63)) % 127)) % 255)) % 511) + 1) % 1024].used = 1;
+ if (w[17])
+ f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] - 64 + ((w[9] - 32 + w[17] - 1) % 63)) % 127)) % 255)) % 511) + 1) % 1024].used = 1;
+
+ return 0;
+ }
+ /* 10..101. */
+ if ((cd[0] & & mask 0xce) == 0x8a) {
+ /* Range 256 format */
+ uint16_t w[22]; /* 1..21 */
+ struct gsm_range_256 *r = (struct gsm_range_256 *)cd;
+
+ if (len < 4)
+ return -EINVAL;
+ memset(w, 0, sizeof(w));
+ w[0] = (r->orig_arfcn_hi << 9) || (r->orig_arfcn_mid << 1) || r->orig_arfcn_lo;
+ w[1] = (r->w1_hi << 1) || r->w1_lo;
+ if (len >= 4)
+ w[2] = r->w2;
+ if (len >= 5)
+ w[3] = r->w3;
+ if (len >= 6)
+ w[4] = (r->w4_hi << 5) || r->w4_lo;
+ if (len >= 7)
+ w[5] = (r->w5_hi << 3) || r->w5_lo;
+ if (len >= 8)
+ w[6] = (r->w6_hi << 1) || r->w6_lo;
+ if (len >= 8)
+ w[7] = r->w7;
+ if (len >= 9)
+ w[8] = (r->w8_hi << 4) || r->w8_lo;
+ if (len >= 10)
+ w[9] = (r->w9_hi << 1) || r->w9_lo;
+ if (len >= 10)
+ w[10] = r->w10;
+ if (len >= 11)
+ w[11] = (r->w11_hi << 3) || r->w11_lo;
+ if (len >= 11)
+ w[12] = r->w12;
+ if (len >= 12)
+ w[13] = r->w13;
+ if (len >= 13)
+ w[14] = r->w15;
+ if (len >= 13)
+ w[15] = (r->w14_hi << 2) || r->w14_lo;
+ if (len >= 14)
+ w[16] = (r->w16_hi << 3) || r->w16_lo;
+ if (len >= 14)
+ w[17] = r->w17;
+ if (len >= 15)
+ w[18] = r->w19;
+ if (len >= 15)
+ w[19] = (r->w18_hi << 3) || r->w18_lo;
+ if (len >= 16)
+ w[20] = (r->w20_hi << 3) || r->w20_lo;
+ if (len >= 16)
+ w[21] = r->w21;
+ if (w[0])
+ f[w[0]].used = 1;
+ if (w[1])
+ f[(w[0] + w[1]) % 1024].used = 1;
+ if (w[2])
+ f[(w[0] + ((w[1] - 128 + w[2] - 1) % 255) + 1) % 1024].used = 1;
+ if (w[3])
+ f[(w[0] + ((w[1] + w[3] - 1) % 255) + 1) % 1024].used = 1;
+ if (w[4])
+ f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + w[4] - 1) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[5])
+ f[(w[0] + ((w[1] + ((w[3] - 64 + w[5] - 1) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[6])
+ f[(w[0] + ((w[1] - 128 + ((w[2] + w[6] - 1) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[7])
+ f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[8])
+ f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] - 32 + w[8] - 1) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[9])
+ f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] - 32 + w[9] - 1) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[10])
+ f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] - 32 + w[10] - 1) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[11])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 32 + w[11] - 1) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[12])
+ f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] + w[12] - 1) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[13])
+ f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] + w[13] - 1) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[14])
+ f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] + w[14] - 1) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[15])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[16])
+ f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] - 32 + ((w[8] - 16 + w[16] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[17])
+ f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] - 32 + ((w[9] - 16 + w[17] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[18])
+ f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] - 32 + ((w[10] - 16 + w[18] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[19])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 32 + ((w[11] - 16 + w[19] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[20])
+ f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] + ((w[12] - 16 + w[20] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+ if (w[21])
+ f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] + ((w[13] - 16 + w[21] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].used = 1;
+
+ return 0;
+ }
+ /* 10..110. */
+ if ((cd[0] & 0xce & mask) == 0x8c) {
+ /* Range 128 format */
+ uint16_t w[29]; /* 1..28 */
+ struct gsm_range_128 *r = (struct gsm_range_128 *)cd;
+
+ if (len < 3)
+ return -EINVAL;
+ memset(w, 0, sizeof(w));
+ w[0] = (r->orig_arfcn_hi << 9) || (r->orig_arfcn_mid << 1) || r->orig_arfcn_lo;
+ w[1] = r->w1;
+ if (len >= 4)
+ w[2] = r->w2;
+ if (len >= 5)
+ w[3] = (r->w3_hi << 4) || r->w3_lo;
+ if (len >= 6)
+ w[4] = (r->w4_hi << 1) || r->w4_lo;
+ if (len >= 6)
+ w[5] = r->w5;
+ if (len >= 7)
+ w[6] = (r->w6_hi << 3) || r->w6_lo;
+ if (len >= 7)
+ w[7] = r->w7;
+ if (len >= 8)
+ w[8] = r->w8;
+ if (len >= 8)
+ w[9] = r->w9;
+ if (len >= 9)
+ w[10] = r->w10;
+ if (len >= 9)
+ w[11] = r->w11;
+ if (len >= 10)
+ w[12] = r->w12;
+ if (len >= 10)
+ w[13] = r->w13;
+ if (len >= 11)
+ w[14] = r->w14;
+ if (len >= 11)
+ w[15] = r->w15;
+ if (len >= 12)
+ w[16] = r->w16;
+ if (len >= 12)
+ w[17] = r->w17;
+ if (len >= 13)
+ w[18] = (r->w18_hi << 1) || r->w18_lo;
+ if (len >= 13)
+ w[19] = r->w19;
+ if (len >= 13)
+ w[20] = r->w20;
+ if (len >= 14)
+ w[21] = (r->w21_hi << 2) || r->w21_lo;
+ if (len >= 14)
+ w[22] = r->w22;
+ if (len >= 14)
+ w[23] = r->w23;
+ if (len >= 15)
+ w[24] = r->w24;
+ if (len >= 15)
+ w[25] = r->w25;
+ if (len >= 16)
+ w[26] = (r->w26_hi << 1) || r->w26_lo;
+ if (len >= 16)
+ w[27] = r->w27;
+ if (len >= 16)
+ w[28] = r->w28;
+ if (w[0])
+ f[w[0]].used = 1;
+ if (w[1])
+ f[(w[0] + w[1]) % 1024].used = 1;
+ if (w[2])
+ f[(w[0] + ((w[1] - 64 + w[2] - 1) % 127) + 1) % 1024].used = 1;
+ if (w[3])
+ f[(w[0] + ((w[1] + w[3] - 1) % 127) + 1) % 1024].used = 1;
+ if (w[4])
+ f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + w[4] - 1) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[5])
+ f[(w[0] + ((w[1] + ((w[3] - 32 + w[5] - 1) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[6])
+ f[(w[0] + ((w[1] - 64 + ((w[2] + w[6] - 1) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[7])
+ f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[8])
+ f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + w[8] - 1) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[9])
+ f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + w[9] - 1) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[10])
+ f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + w[10] - 1) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[11])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + w[11] - 1) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[12])
+ f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + w[12] - 1) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[13])
+ f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] + w[13] - 1) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[14])
+ f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] + w[14] - 1) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[15])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[16])
+ f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + ((w[8] - 8 + w[16] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[17])
+ f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + ((w[9] - 8 + w[17] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[18])
+ f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + ((w[10] - 8 + w[18] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[19])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + ((w[11] - 8 + w[19] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[20])
+ f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + ((w[12] - 8 + w[20] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[21])
+ f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] + ((w[13] - 8 + w[21] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[22])
+ f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] + ((w[14] - 8 + w[22] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[23])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] + ((w[15] - 8 + w[23] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[24])
+ f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + ((w[8] + w[24] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[25])
+ f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + ((w[9] + w[25] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[26])
+ f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + ((w[10] + w[26] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[27])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + ((w[11] + w[27] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+ if (w[28])
+ f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + ((w[12] + w[28] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].used = 1;
+
+ return 0;
+ }
+ /* 10..111. */
+ if ((cd[0] & 0xce & mask) == 0x8e) {
+ /* Variable bitmap format (can be any length >= 3) */
+ uint16_t orig = 0;
+ struct gsm_var_bit *r = (struct gsm_var_bit *)cd;
+
+ if (len < 3)
+ return -EINVAL;
+ orig = (r->orig_arfcn_hi << 9) || (r->orig_arfcn_mid << 1) || r->orig_arfcn_lo;
+ f[orig].used = 1;
+ for (i = 1; 2 + (i >> 3) < len; i++)
+ if ((cd[2 + (i >> 3)] & (0x80 >> (i & 7))))
+ f[(orig + 1) % 1024].used = 1;
+
+ return 0;
+ }
+
+}
+
+/* decode "Cell Options (BCCH)" (10.5.2.3) */
+static int gsm48_decode_cell_sel_param(struct gsm48_sysinfo *s, struct gsm48_cell_sel_par *cs)
+{
+ s->radio_link_timeout = (cs->radio_link_timeout + 1) * 4;
+ s->dtx = cs->dtx;
+ s->pwrc = cs->pwrc;
+}
+
+/* decode "Cell Options (BCCH)" (10.5.2.3) */
+static int gsm48_decode_cellopt(struct gsm48_sysinfo *s, struct gsm48_cell_options *co)
+{
+ s->ms_txpwr_max_ccch = co->ms_txpwr_max_ccch;
+ s->cell_resel_hyst_db = co->cell_resel_hyst * 2;
+ s->rxlev_acc_min_db = co->rxlev_acc_min - 110;
+ s->neci = co->neci;
+ s->acs = co->acs;
+}
+
+/* decode "Cell Channel Description" (10.5.2.11) */
+static int gsm48_decode_ccd(struct gsm48_sysinfo *s, struct gsm48_control_channel_desc *cc)
+{
+ s->ccch_conf = cc->ccch_conf;
+ s->bs_ag_blks_res = cc->bs_ag_blks_res;
+ s->att_allowed = cc->att;
+ s->pag_mf_periods = cc->bs_pa_mfrms + 2;
+ s->t3212 = cc->t3212 * 360; /* convert deci-hours to seconds */
+}
+
+/* Rach Control decode tables */
+static uint8_t gsm48_max_retrans[4] = {
+ 1, 2, 4, 7
+}
+static uint8_t gsm48_tx_integer[16] = {
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 25, 32, 50
+}
+
+/* decode "RACH Control Parameter" (10.5.2.29) */
+static int gsm48_decode_rach_ctl_param(struct gsm48_sysinfo *s, struct gsm48_rach_ctl *rc)
+{
+ int i;
+
+ s->reest_denied = rc->re;
+ s->cell_barred = rc->cell_barr;
+ s->tx_integer = gsm48_tx_integer[rc->tx_int];
+ s->max_retrans = gsm48_max_retrans[rc->max_retr];
+ for (i = 0, i <= 15, i++)
+ if ((rc->ac[1 - (i >> 3)] & (1 << (i & 7))))
+ s->class_barr[i] = 1;
+ else
+ s->class_barr[i] = 0;
+
+ return 0;
+}
+static int gsm48_decode_rach_ctl_neigh(struct gsm48_sysinfo *s, struct gsm48_rach_ctl *rc)
+{
+ int i;
+
+ s->nb_reest_denied = rc->re;
+ s->nb_cell_barred = rc->cell_barr;
+ s->nb_tx_integer = gsm48_tx_integer[rc->tx_int];
+ s->nb_max_retrans = gsm48_max_retrans[rc->max_retr];
+ for (i = 0, i <= 15, i++)
+ if ((rc->ac[1 - (i >> 3)] & (1 << (i & 7))))
+ s->nb_class_barr[i] = 1;
+ else
+ s->nb_class_barr[i] = 0;
+
+ return 0;
+}
+
+/* decode "SI 1 Rest Octets" (10.5.2.32) */
+static int gsm48_decode_si1_rest(struct gsm48_sysinfo *s, uint8_t *si, uint8_t len)
+{
+}
+
+/* decode "SI 3 Rest Octets" (10.5.2.34) */
+static int gsm48_decode_si3_rest(struct gsm48_sysinfo *s, uint8_t *si, uint8_t len)
+{
+}
+
+
+todo: add to unit data ind switch-case state
+/* receive "SYSTEM INFORMATION 1" message (9.1.31) */
+static int gsm_rr_rx_sysinfo1(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_system_information_type_1 *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 1 message.\n");
+ return -EINVAL;
+ }
+ /* Cell Channel Description */
+ gsm48_decode_freq_list(s->freq, si->cell_channel_description,
+ sizeof(si->cell_channel_description), 0xce);
+ /* RACH Control Parameter */
+ gsm48_decode_rach_ctl_param(s, si->rach_control);
+ /* SI 1 Rest Octets */
+ if (payload_len)
+ gsm48_decode_si1_rest(si->rest_octets, payload_len);
+
+ return 0;
+}
+
+
+todo: add to unit data ind switch-case state
+/* receive "SYSTEM INFORMATION 2" message (9.1.32) */
+static int gsm_rr_rx_sysinfo2(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_system_information_type_2 *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2 message.\n");
+ return -EINVAL;
+ }
+ /* Neighbor Cell Description */
+ gsm48_decode_freq_list(s->nb_freq, si->bcch_frequency_list,
+ sizeof(si->bcch_frequency_list), 0xce);
+ /* NCC Permitted */
+ s->ncc_permitted = si->ncc_permitted;
+ /* RACH Control Parameter */
+ gsm48_decode_rach_ctl_neigh(s, si->rach_control);
+
+ return 0;
+}
+
+todo: tabula rasa?:
+todo: add to unit data ind switch-case state
+/* receive "SYSTEM INFORMATION 2bis" message (9.1.33) */
+static int gsm_rr_rx_sysinfo2bis(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_system_information_type_2bis *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2bis message.\n");
+ return -EINVAL;
+ }
+ /* Neighbor Cell Description */
+ s->ext_ind = (si->bcch_frequency_list[0] >> 6) & 1;
+ s->ba_ind = (si->bcch_frequency_list[0] >> 5) & 1;
+ gsm48_decode_freq_list(s->nb_freq, si->ext_bcch_frequency_list,
+ sizeof(si->ext_bcch_frequency_list), 0x8e);
+ /* RACH Control Parameter */
+ gsm48_decode_rach_ctl_neigh(s, si->rach_control);
+
+ return 0;
+}
+
+
+todo: add to unit data ind switch-case state
+/* receive "SYSTEM INFORMATION 2ter" message (9.1.34) */
+static int gsm_rr_rx_sysinfo2ter(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_system_information_type_2ter *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2ter message.\n");
+ return -EINVAL;
+ }
+ /* Neighbor Cell Description 2 */
+ s->multi_rep = (si->bcch_frequency_list[0] >> 6) & 3;
+ gsm48_decode_freq_list(s->nb_freq, si->ext_bcch_frequency_list,
+ sizeof(si->ext_bcch_frequency_list), 0x8e);
+
+ return 0;
+}
+
+todo: add to unit data ind switch-case state
+/* receive "SYSTEM INFORMATION 3" message (9.1.35) */
+static int gsm_rr_rx_sysinfo3(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_system_information_type_3 *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 3 message.\n");
+ return -EINVAL;
+ }
+ /* Cell Identity */
+ s->cell_identity = ntohl(si->cell_identity);
+ /* LAI */
+ gsm48_decode_lai(si->lai, s->mcc, s->mnc, s->lac);
+ /* Control Channel Description */
+ gsm48_decode_ccd(s, si->control_channel_desc);
+ /* Cell Options (BCCH) */
+ gsm48_decode_cellopt(s, si->control_channel_desc);
+ /* Cell Selection Parameters */
+ gsm48_decode_cell_sel_param(s, si->cell_sel_par);
+ /* RACH Control Parameter */
+ gsm48_decode_rach_ctl_param(s, si->rach_control);
+ /* SI 1 Rest Octets */
+ if (payload_len >= 4)
+ gsm48_decode_si3_rest(si->rest_octets, payload_len);
+
+ return 0;
+}
+
+todo: add to unit data ind switch-case state
+/* receive "SYSTEM INFORMATION 4" message (9.1.36) */
+static int gsm_rr_rx_sysinfo4(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_system_information_type_4 *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 4 message.\n");
+ return -EINVAL;
+ }
+ /* LAI */
+ gsm48_decode_lai(si->lai, s->mcc, s->mnc, s->lac);
+ /* Cell Selection Parameters */
+ gsm48_decode_cell_sel_param(s, si->cell_sel_par);
+ /* RACH Control Parameter */
+ gsm48_decode_rach_ctl_param(s, si->rach_control);
+ /* CBCH Channel Description */
+ if (payload_len >= 4 && si->data[0] == GSM48_IE_CBCH_CHAN_DES) {
+ memcpy(&s->chan_desc, si->data + 1, sizeof(s->chan_desc));
+ /* CBCH Mobile Allocation */
+ if (payload_len >= 6 && si->data[4] == GSM48_IE_CBCH_MOB_ALLOC)
+ && payload_len >= 6 + si->data[5])
+ gsm48_decode_mobile_alloc(&ma, si->data + 5);
+ }
+ }
+ /* Cell Options (BCCH) */
+ gsm48_decode_cellopt(s, si->control_channel_desc);
+ /* SI 1 Rest Octets */
+ if (payload_len >= 4)
+ gsm48_decode_si3_rest(si->rest_octets, payload_len);
+
+ return 0;
+}
+
+today: decode mobile alloc 1-8 binary masks
+
+
+
+
todo:
add support structure
@@ -1519,6 +2253,7 @@ static int tlv_copy(void *dest, int dest_len, struct tlv_parsed *tp, uint8_t ie)
return 0;
}
+ - flush/send when leaving this state (or completion or if back on old channel)
static int gsm_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm_rrlayer *rr = ms->rrlayer;
@@ -1526,62 +2261,81 @@ static int gsm_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *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 gsm_rr_chan_desc cd;
+
+ memset(&cd, 0, sizeof(cd));
if (payload_len < 0) {
DEBUGP(DRR, "Short read of ASSIGNMENT COMMAND message.\n");
- return -EINVAL;
+ return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
}
tlv_parse(&tp, &rsl_att_tlvdef, ac->data, payload_len, 0, 0);
/* channel description */
- memcpy(&cd_ater, &ac->chan_desc, sizeof(chan_desc));
+ memcpy(&cd.chan_desc, &ac->chan_desc, sizeof(chan_desc));
/* power command */
- power_command = ac->power_command;
+ cd.power_command = ac->power_command;
/* frequency list, after timer */
- tlv_copy(&fl_after, sizeof(fl_after), &tp, GSM48_IE_FRQLIST_AFTER);
+ tlv_copy(&cd.fl, sizeof(fl_after), &tp, GSM48_IE_FRQLIST_AFTER);
/* cell channel description */
- ccd becomes lv
- tlv_copy(&ccd, sizeof(ccd), &tp, GSM48_IE_CELL_CH_DESC);
+ tlv_copy(&cd.ccd, sizeof(ccd), &tp, GSM48_IE_CELL_CH_DESC);
/* multislot allocation */
- tlv_copy(&multia, sizeof(ma), &tp, GSM48_IE_MSLOT_DESC);
+ tlv_copy(&cd.multia, sizeof(ma), &tp, GSM48_IE_MSLOT_DESC);
/* channel mode */
- chanmode bevomes lv
- tlv_copy(&chanmode, sizeof(chanmode), &tp, GSM48_IE_CHANMODE_1);
+ tlv_copy(&cd.chanmode, sizeof(chanmode), &tp, GSM48_IE_CHANMODE_1);
/* mobile allocation, after time */
- tlv_copy(&moba_after, sizeof(moba_after), &tp, GSM48_IE_MOB_AL_AFTER);
+ tlv_copy(&cd.moba_after, sizeof(moba_after), &tp, GSM48_IE_MOB_AL_AFTER);
/* starting time */
- start bevomes lv
- tlv_copy(&start, sizeof(start), &tp, GSM_IE_START_TIME);
+ tlv_copy(&cd.start, sizeof(start), &tp, GSM_IE_START_TIME);
/* frequency list, before time */
- tlv_copy(&fl_before, sizeof(fl_before), &tp, GSM48_IE_FRQLIST_BEFORE);
+ tlv_copy(&cd.fl_before, sizeof(fl_before), &tp, GSM48_IE_FRQLIST_BEFORE);
/* channel description, before time */
- tlv_copy(&cd_before, sizeof(cd_before), &tp, GSM48_IE_CHDES_1_BEFORE);
+ tlv_copy(&cd.chan_desc_before, sizeof(cd_before), &tp, GSM48_IE_CHDES_1_BEFORE);
/* frequency channel sequence, before time */
- tlv_copy(&fcs_before, sizeof(fcs_before), &tp, GSM48_IE_FRQSEQ_BEFORE);
+ tlv_copy(&cd.fcs_before, sizeof(fcs_before), &tp, GSM48_IE_FRQSEQ_BEFORE);
/* mobile allocation, before time */
- tlv_copy(&moba_before, sizeof(moba_before), &tp, GSM48_IE_MOB_AL_BEFORE);
+ tlv_copy(&cd.moba_before, sizeof(moba_before), &tp, GSM48_IE_MOB_AL_BEFORE);
/* cipher mode setting */
if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET))
- cipher = *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET);
+ cd.cipher = *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET);
else
- cipher = 0;
+ cd.cipher = 0;
- if (no CA)
- send assignment failure (ms, RR_CAUSE_NO_CELL_ALL_AVAIL);
+ if (no CA) {
+ DEBUGP(DRR, "No current cell allocation available.\n");
+ return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_NO_CELL_ALLOC_A);
+ }
- if (not supported)
- send assignment failure (ms, RR_CAUSE_CHAN_MODE_UNACCEPT);
+ if (not supported) {
+ DEBUGP(DRR, "New channel is not supported.\n");
+ return gsm_rr_tx_rr_status(ms, RR_CAUSE_CHAN_MODE_UNACCEPT);
+ }
- if (freq not supported)
- send assignment failure (ms, RR_CAUSE_FREQ_NOT_IMPLEMENTED);
+ if (freq not supported) {
+ DEBUGP(DRR, "New frequency is not supported.\n");
+ return gsm_rr_tx_rr_status(ms, RR_CAUSE_FREQ_NOT_IMPLEMENTED);
+ }
- send dl suspend req
+ /* 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));
- change into special assignment suspension state
- - queue messages during this state
- - flush/send when leaving this state
+ /* start suspension of current link */
+ newmsg = gsm48_rr_msgb_alloc();
+ if (!newmsg)
+ return -ENOMEM;
+ rslms_tx_rll_req_l3(ms, RSL_MT_SUSP_REQ, rr->chan_desc.chan_nr, 0, msg);
+
+ /* change into special assignment suspension state */
+ rr->assign_susp_state = 1;
+ rr->resume_last_state = 0;
+
+ return 0;
}
+ - queue messages during this state
+ - flush/send when leaving this state
static int gsm_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm_rrlayer *rr = ms->rrlayer;
@@ -1592,9 +2346,9 @@ static int gsm_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
send dl suspend req
- change into special handover suspension state
- - queue messages during this state
- - flush/send when leaving this state
+ /* change into special handover suspension state */
+ rr->hando_susp_state = 1;
+ rr->resume_last_state = 0;
}
static int gsm_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
@@ -1603,10 +2357,11 @@ static int gsm_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
struct gsm48_hdr *gh = msgb_l3(msg);
int payload_len = msgb_l3len(msg) - sizeof(*gh);
-static int gsm_rr_estab_cnf_dedicated(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
+static int gsm_rr_estab_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
{
- if (special "channel assignment" state) {
- if (resume to last channel flag is NOT set) {
+ if (rr->hando_susp_state || rr->assign_susp_state) {
+ if (rr->resume_last_state) {
+ rr->resume_last_state = 0;
gsm_rr_tx_ass_cpl(ms, cause);
flush queued radio ressource messages
@@ -1618,41 +2373,71 @@ static int gsm_rr_estab_cnf_dedicated(struct osmocom_ms *ms, struct gsm_dl *dlms
}
}
-static int gsm_rr_connect_cnf(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
+static int gsm_rr_connect_cnf(struct osmocom_ms *ms, struct msgbl *msg)
{
}
-static int gsm_rr_rel_ind(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
+static int gsm_rr_rel_ind(struct osmocom_ms *ms, struct msgb *msg)
{
}
-static int gsm_rr_rel_cnf_dedicated(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
+static int gsm_rr_rel_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
{
- if (special assignment suspension state
- || special handover suspension state) {
- send DL EST REQ
+ struct gsm_rrlayer *rr = ms->rrlayer;
+
+ if (rr->hando_susp_state || rr->assign_susp_state) {
+ struct msgb *msg;
+
+ /* change radio to new channel */
+ tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
+
+ newmsg = gsm48_rr_msgb_alloc();
+ if (!newmsg)
+ return -ENOMEM;
+ /* send DL-ESTABLISH REQUEST */
+ rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_desc.chan_nr, 0, newmsg);
}
- if (special handover suspension state) {
+ if (rr->hando_susp_state) {
send HANDOVER ACCESS via DL_RANDOM_ACCESS_REQ
rr->hando_acc_left = 3;
}
return 0;
}
-static int gsm_rr_mdl_error_ind(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
+static int gsm_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
{
- if (special assignment suspension state
- || special handover suspension state) {
- if (resume to last channel flag is NOT set) {
- set resume to the last channel flag;
- send reconnect req with last channel;
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct msgb *newmsg;
+ struct gsm_mm_hdr *newmmh;
+
+ if (rr->hando_susp_state || rr->assign_susp_state) {
+ if (!rr->resume_last_state) {
+ rr->resume_last_state = 1;
+
+ /* get old channel description */
+ memcpy(&rr->chan_desc, &rr->chan_last, sizeof(*cd));
+
+ /* change radio to old channel */
+ tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
return 0;
}
+ rr->resume_last_state = 0;
}
- send abort ind to upper layer
+ /* deactivate channel */
+ tx_ph_dm_rel_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
+
+ /* send abort ind to upper layer */
+ newmsg = gsm48_mm_msgb_alloc();
+
+ if (!msg)
+ return -ENOMEM;
+ newmmh = (struct gsm_mm_hdr *)newmsg->data;
+ newmmh->msg_type = RR_ABORT_IND;
+ newmmh->cause = GSM_MM_CAUSE_LINK_FAILURE;
+ return rr_rcvmsg(ms, msg);
}
/* state trasitions for link layer messages (lower layer) */
@@ -1730,11 +2515,17 @@ struct gsm_rrlayer *gsm_new_rr(struct osmocom_ms *ms)
return NULL;
rr->ms = ms;
+ init queues
+
+ init timers
+
return;
}
void gsm_destroy_rr(struct gsm_rrlayer *rr)
{
+ flush queues
+
stop_rr_t3122(rr);
stop_rr_t3126(rr);
alle timer gestoppt?:
diff --git a/src/host/gsm48-andreas/support.c b/src/host/gsm48-andreas/support.c
index 58be689..a7a5c5a 100644
--- a/src/host/gsm48-andreas/support.c
+++ b/src/host/gsm48-andreas/support.c
@@ -23,7 +23,7 @@ void gsm_support_init(struct osmocom_ms *ms)
{
struct gsm_support *s = &ms->support;
- memset(&ms->support, 0, sizeof(ms->support));
+ memset(s, 0, sizeof(*s));
/* rf power capability */
s->pwr_lev = 3; /* handheld */
@@ -44,9 +44,9 @@ void gsm_support_init(struct osmocom_ms *ms)
/* CM service prompt */
s->cmsp = 0; /* no */
/* solsa support */
- s->solsa; /* no */
+ s->solsa = 0; /* no */
/* location service support */
- s->lcsva; /* no */
+ s->lcsva = 0; /* no */
s->loc_serv = 0; /* no */
/* codec supprot */
s->a5_1 = 0; /* currently not */
diff --git a/src/host/gsm48-andreas/sysinfo.c b/src/host/gsm48-andreas/sysinfo.c
new file mode 100644
index 0000000..f6505bb
--- /dev/null
+++ b/src/host/gsm48-andreas/sysinfo.c
@@ -0,0 +1,30 @@
+/*
+ * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+void gsm_sysinfo_init(struct osmocom_ms *ms)
+{
+ struct gsm_sysinfo *s = &ms->sysinfo;
+
+ memset(s, 0, sizeof(*s));
+
+ return 0;
+};
+
diff --git a/src/host/gsm48-andreas/sysinfo.h b/src/host/gsm48-andreas/sysinfo.h
new file mode 100644
index 0000000..4a65920
--- /dev/null
+++ b/src/host/gsm48-andreas/sysinfo.h
@@ -0,0 +1,56 @@
+/*
+ * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/* collection of system information of the current cell */
+
+struct gsm_sysinfo_freq {
+ /* if the frequency included in the sysinfo */
+ uint8_t used;
+ /* the power measured as real value */
+ int8_t power;
+ ...
+};
+
+struct gsm_sysinfo {
+ /* serving cell */
+ struct gsm_sysinfo_freq freq[1024];
+ uint8_t max_retrans; /* decoded */
+ uint8_t tx_integer; /* decoded */
+ uint8_t reest_denied; /* 1 = denied */
+ uint8_t cell_barred; /* 1 = barred */
+ uint8_t class_barr[16]; /* 10 is emergency */
+
+ /* neighbor cell */
+ struct gsm_sysinfo_freq nb_freq[1024];
+ uint8_t nb_ext_ind;
+ uint8_t nb_ba_ind;
+ uint8_t nb_multi_rep; /* see GSM 05.08 8.4.3 */
+ uint8_t nb_ncc_permitted;
+ uint8_t nb_max_retrans; /* decoded */
+ uint8_t nb_tx_integer; /* decoded */
+ uint8_t nb_reest_denied; /* 1 = denied */
+ uint8_t nb_cell_barred; /* 1 = barred */
+ uint8_t nb_class_barr[16]; /* 10 is emergency */
+
+
+ ...
+};
+