summaryrefslogtreecommitdiffstats
path: root/src/host/layer23
diff options
context:
space:
mode:
authorAndreas.Eversberg <jolly@eversberg.eu>2010-10-24 12:30:37 +0000
committerAndreas.Eversberg <jolly@eversberg.eu>2010-10-24 12:30:37 +0000
commit1ac1852ffc806708f86a50073b9661a9ed19c336 (patch)
tree8bf851d1ac7bca52957bdbb06bf140268d842f5d /src/host/layer23
parentc0500693a6e5cb764a0c80a61d0166dbbcfa3cad (diff)
[layer23] Moving decoding of SYSTEM INFORMATION to sysinfo.c
This way the decoding can be re-used by other applications.
Diffstat (limited to 'src/host/layer23')
-rw-r--r--src/host/layer23/include/osmocom/bb/mobile/sysinfo.h29
-rw-r--r--src/host/layer23/src/mobile/gsm48_rr.c436
-rw-r--r--src/host/layer23/src/mobile/sysinfo.c513
3 files changed, 564 insertions, 414 deletions
diff --git a/src/host/layer23/include/osmocom/bb/mobile/sysinfo.h b/src/host/layer23/include/osmocom/bb/mobile/sysinfo.h
index 070135db..07daafa7 100644
--- a/src/host/layer23/include/osmocom/bb/mobile/sysinfo.h
+++ b/src/host/layer23/include/osmocom/bb/mobile/sysinfo.h
@@ -116,5 +116,34 @@ struct gsm48_sysinfo {
int gsm48_sysinfo_dump(struct gsm48_sysinfo *s, uint16_t arfcn,
void (*print)(void *, const char *, ...), void *priv);
+int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc,
+ uint16_t *mnc, uint16_t *lac);
+int gsm48_decode_chan_h0(struct gsm48_chan_desc *cd, uint8_t *tsc,
+ uint16_t *arfcn);
+int gsm48_decode_chan_h1(struct gsm48_chan_desc *cd, uint8_t *tsc,
+ uint8_t *maio, uint8_t *hsn);
+int gsm48_decode_sysinfo1(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_1 *si, int len);
+int gsm48_decode_sysinfo2(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_2 *si, int len);
+int gsm48_decode_sysinfo2bis(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_2bis *si, int len);
+int gsm48_decode_sysinfo2ter(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_2ter *si, int len);
+int gsm48_decode_sysinfo3(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_3 *si, int len);
+int gsm48_decode_sysinfo4(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_4 *si, int len);
+int gsm48_decode_sysinfo5(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_5 *si, int len);
+int gsm48_decode_sysinfo5bis(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_5bis *si, int len);
+int gsm48_decode_sysinfo5ter(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_5ter *si, int len);
+int gsm48_decode_sysinfo6(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_6 *si, int len);
+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);
#endif /* _SYSINFO_H */
diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c
index 78c99310..d71d4256 100644
--- a/src/host/layer23/src/mobile/gsm48_rr.c
+++ b/src/host/layer23/src/mobile/gsm48_rr.c
@@ -95,20 +95,6 @@ static int gsm48_rr_rel_cnf(struct osmocom_ms *ms, struct msgb *msg);
#define MIN(a, b) ((a < b) ? a : b)
-int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc,
- uint16_t *mnc, uint16_t *lac)
-{
- *mcc = ((lai->digits[0] & 0x0f) << 8)
- | (lai->digits[0] & 0xf0)
- | (lai->digits[1] & 0x0f);
- *mnc = ((lai->digits[2] & 0x0f) << 8)
- | (lai->digits[2] & 0xf0)
- | ((lai->digits[1] & 0xf0) >> 4);
- *lac = ntohs(lai->lac);
-
- return 0;
-}
-
int gsm48_encode_lai(struct gsm48_loc_area_id *lai, uint16_t mcc,
uint16_t mnc, uint16_t lac)
{
@@ -120,25 +106,6 @@ int gsm48_encode_lai(struct gsm48_loc_area_id *lai, uint16_t mcc,
return 0;
}
-static int gsm48_decode_chan_h0(struct gsm48_chan_desc *cd, uint8_t *tsc,
- uint16_t *arfcn)
-{
- *tsc = cd->h0.tsc;
- *arfcn = cd->h0.arfcn_low | (cd->h0.arfcn_high << 8);
-
- return 0;
-}
-
-static int gsm48_decode_chan_h1(struct gsm48_chan_desc *cd, uint8_t *tsc,
- uint8_t *maio, uint8_t *hsn)
-{
- *tsc = cd->h1.tsc;
- *maio = cd->h1.maio_low | (cd->h1.maio_high << 2);
- *hsn = cd->h1.hsn;
-
- 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)
@@ -1594,218 +1561,6 @@ fail:
* system information
*/
-/* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */
-static int decode_freq_list(struct gsm_settings *set,
- struct gsm_sysinfo_freq *f, uint8_t *cd, uint8_t len, uint8_t mask,
- uint8_t frqt)
-{
- /* only Bit map 0 format for P-GSM */
- if ((cd[0] & 0xc0 & mask) != 0x00 &&
- (set->p_gsm && !set->e_gsm && !set->r_gsm && !set->dcs))
- return 0;
-
- return gsm48_decode_freq_list(f, cd, len, mask, frqt);
-}
-
-/* decode "Cell Selection Parameters" (10.5.2.4) */
-static int gsm48_decode_cell_sel_param(struct gsm48_sysinfo *s,
- struct gsm48_cell_sel_par *cs)
-{
-#ifdef TODO
- convert ms_txpwr_max_ccch dependant on the current frequenc and support
- to the right powe level
-#endif
- s->ms_txpwr_max_cch = cs->ms_txpwr_max_ccch;
- s->cell_resel_hyst_db = cs->cell_resel_hyst * 2;
- s->rxlev_acc_min_db = cs->rxlev_acc_min - 110;
- s->neci = cs->neci;
- s->acs = cs->acs;
-
- return 0;
-}
-
-/* decode "Cell Options (BCCH)" (10.5.2.3) */
-static int gsm48_decode_cellopt_bcch(struct gsm48_sysinfo *s,
- struct gsm48_cell_options *co)
-{
- s->bcch_radio_link_timeout = (co->radio_link_timeout + 1) * 4;
- s->bcch_dtx = co->dtx;
- s->bcch_pwrc = co->pwrc;
-
- return 0;
-}
-
-/* decode "Cell Options (SACCH)" (10.5.2.3a) */
-static int gsm48_decode_cellopt_sacch(struct gsm48_sysinfo *s,
- struct gsm48_cell_options *co)
-{
- s->sacch_radio_link_timeout = (co->radio_link_timeout + 1) * 4;
- s->sacch_dtx = co->dtx;
- s->sacch_pwrc = co->pwrc;
-
- return 0;
-}
-
-/* decode "Control Channel Description" (10.5.2.11) */
-static int gsm48_decode_ccd(struct gsm48_sysinfo *s,
- struct gsm48_control_channel_descr *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 */
-
- return 0;
-}
-
-/* decode "Mobile Allocation" (10.5.2.21) */
-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;
- uint16_t f[len << 3];
-
- /* not more than 64 hopping indexes allowed in IE */
- if (len > 8)
- return -EINVAL;
-
- /* tabula rasa */
- *hopp_len = 0;
- if (si4) {
- for (i = 0; i < 1024; i++)
- freq[i].mask &= ~FREQ_TYPE_HOPP;
- }
-
- /* generating list of all frequencies (1..1023,0) */
- for (i = 1; i <= 1024; i++) {
- 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;
- if (j == (len << 3))
- break;
- }
- }
-
- /* fill hopping table with frequency index given by IE
- * and set hopping type bits
- */
- for (i = 0; i < (len << 3); i++) {
- /* if bit is set, this frequency index is used for hopping */
- if ((ma[len - 1 - (i >> 3)] & (1 << (i & 7)))) {
- LOGP(DRR, LOGL_INFO, "Hopping ARFCN: %d (bit %d)\n",
- i, f[i]);
- /* index higher than entries in list ? */
- if (i >= j) {
- LOGP(DRR, LOGL_NOTICE, "Mobile Allocation "
- "hopping index %d exceeds maximum "
- "number of cell frequencies. (%d)\n",
- i + 1, j);
- break;
- }
- hopping[(*hopp_len)++] = f[i];
- if (si4)
- freq[f[i]].mask |= FREQ_TYPE_HOPP;
- }
- }
-
- return 0;
-}
-
-/* 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_control *rc)
-{
- s->reest_denied = rc->re;
- s->cell_barr = rc->cell_bar;
- s->tx_integer = gsm48_tx_integer[rc->tx_integer];
- s->max_retrans = gsm48_max_retrans[rc->max_trans];
- s->class_barr = (rc->t2 << 8) | rc->t3;
-
- return 0;
-}
-static int gsm48_decode_rach_ctl_neigh(struct gsm48_sysinfo *s,
- struct gsm48_rach_control *rc)
-{
- s->nb_reest_denied = rc->re;
- s->nb_cell_barr = rc->cell_bar;
- s->nb_tx_integer = gsm48_tx_integer[rc->tx_integer];
- s->nb_max_retrans = gsm48_max_retrans[rc->max_trans];
- s->nb_class_barr = (rc->t2 << 8) | rc->t3;
-
- 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)
-{
- return 0;
-}
-
-/* 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)
-{
- struct bitvec bv;
-
- memset(&bv, 0, sizeof(bv));
- bv.data_len = len;
- bv.data = si;
-
- /* Optional Selection Parameters */
- if (bitvec_get_bit_high(&bv) == H) {
- s->sp = 1;
- s->sp_cbq = bitvec_get_uint(&bv, 1);
- s->sp_cro = bitvec_get_uint(&bv, 6);
- s->sp_to = bitvec_get_uint(&bv, 3);
- s->sp_pt = bitvec_get_uint(&bv, 5);
- }
- /* Optional Power Offset */
- if (bitvec_get_bit_high(&bv) == H) {
- s->po = 1;
- s->po_value = bitvec_get_uint(&bv, 3);
- }
- /* System Onformation 2ter Indicator */
- if (bitvec_get_bit_high(&bv) == H)
- s->si2ter_ind = 1;
- /* Early Classark Sending Control */
- if (bitvec_get_bit_high(&bv) == H)
- s->ecsm = 1;
- /* Scheduling if and where */
- if (bitvec_get_bit_high(&bv) == H) {
- s->sched = 1;
- s->sched_where = bitvec_get_uint(&bv, 3);
- }
- /* GPRS Indicator */
- s->gi_ra_colour = bitvec_get_uint(&bv, 3);
- s->gi_si13_pos = bitvec_get_uint(&bv, 1);
- return 0;
-}
-
-/* decode "SI 4 Rest Octets" (10.5.2.35) */
-static int gsm48_decode_si4_rest(struct gsm48_sysinfo *s, uint8_t *si,
- uint8_t len)
-{
- return 0;
-}
-
-/* decode "SI 6 Rest Octets" (10.5.2.35a) */
-static int gsm48_decode_si6_rest(struct gsm48_sysinfo *s, uint8_t *si,
- uint8_t len)
-{
- return 0;
-}
-
/* send sysinfo event to other layers */
static int gsm48_new_sysinfo(struct osmocom_ms *ms, uint8_t type)
{
@@ -1819,10 +1574,7 @@ static int gsm48_new_sysinfo(struct osmocom_ms *ms, uint8_t type)
|| type == GSM48_MT_RR_SYSINFO_5bis
|| type == GSM48_MT_RR_SYSINFO_5ter)
&& s->si5
- && (!s->nb_ext_ind_si5
- || (s->si5bis && s->nb_ext_ind_si5 && !s->nb_ext_ind_si5bis)
- || (s->si5bis && s->si5ter && s->nb_ext_ind_si5
- && s->nb_ext_ind_si5bis))) {
+ && (!s->nb_ext_ind_si5 || s->si5bis)) {
struct gsm48_rr_meas *rrmeas = &ms->rrlayer.meas;
int n = 0, i;
@@ -1884,21 +1636,10 @@ static int gsm48_rr_rx_sysinfo1(struct osmocom_ms *ms, struct msgb *msg)
if (!memcmp(si, s->si1_msg, MIN(msgb_l3len(msg), sizeof(s->si1_msg))))
return 0;
- memcpy(s->si1_msg, si, MIN(msgb_l3len(msg), sizeof(s->si1_msg)));
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 1\n");
-
- /* Cell Channel Description */
- decode_freq_list(&ms->settings, s->freq,
- si->cell_channel_description,
- sizeof(si->cell_channel_description), 0xce, FREQ_TYPE_SERV);
- /* RACH Control Parameter */
- gsm48_decode_rach_ctl_param(s, &si->rach_control);
- /* SI 1 Rest Octets */
- if (payload_len)
- gsm48_decode_si1_rest(s, si->rest_octets, payload_len);
+ gsm48_decode_sysinfo1(s, si, msgb_l3len(msg));
- s->si1 = 1;
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 1\n");
return gsm48_new_sysinfo(ms, si->header.system_information);
}
@@ -1924,21 +1665,10 @@ static int gsm48_rr_rx_sysinfo2(struct osmocom_ms *ms, struct msgb *msg)
if (!memcmp(si, s->si2_msg, MIN(msgb_l3len(msg), sizeof(s->si2_msg))))
return 0;
- memcpy(s->si2_msg, si, MIN(msgb_l3len(msg), sizeof(s->si2_msg)));
-
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2\n");
- /* Neighbor Cell Description */
- s->nb_ext_ind_si2 = (si->bcch_frequency_list[0] >> 6) & 1;
- s->nb_ba_ind_si2 = (si->bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->settings, s->freq, si->bcch_frequency_list,
- sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_NCELL_2);
- /* NCC Permitted */
- s->nb_ncc_permitted_si2 = si->ncc_permitted;
- /* RACH Control Parameter */
- gsm48_decode_rach_ctl_neigh(s, &si->rach_control);
+ gsm48_decode_sysinfo2(s, si, msgb_l3len(msg));
- s->si2 = 1;
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2\n");
return gsm48_new_sysinfo(ms, si->header.system_information);
}
@@ -1962,23 +1692,12 @@ static int gsm48_rr_rx_sysinfo2bis(struct osmocom_ms *ms, struct msgb *msg)
return -EINVAL;
}
- if (!memcmp(si, s->si2b_msg, MIN(msgb_l3len(msg),
- sizeof(s->si2b_msg))))
+ if (!memcmp(si, s->si2b_msg, MIN(msgb_l3len(msg), sizeof(s->si2b_msg))))
return 0;
- memcpy(s->si2b_msg, si, MIN(msgb_l3len(msg), sizeof(s->si2b_msg)));
-
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2bis\n");
- /* Neighbor Cell Description */
- s->nb_ext_ind_si2bis = (si->bcch_frequency_list[0] >> 6) & 1;
- s->nb_ba_ind_si2bis = (si->bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->settings, s->freq,
- si->bcch_frequency_list,
- sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_NCELL_2bis);
- /* RACH Control Parameter */
- gsm48_decode_rach_ctl_neigh(s, &si->rach_control);
+ gsm48_decode_sysinfo2bis(s, si, msgb_l3len(msg));
- s->si2bis = 1;
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2bis\n");
return gsm48_new_sysinfo(ms, si->header.system_information);
}
@@ -2002,22 +1721,12 @@ static int gsm48_rr_rx_sysinfo2ter(struct osmocom_ms *ms, struct msgb *msg)
return -EINVAL;
}
- if (!memcmp(si, s->si2t_msg, MIN(msgb_l3len(msg),
- sizeof(s->si2t_msg))))
+ if (!memcmp(si, s->si2t_msg, MIN(msgb_l3len(msg), sizeof(s->si2t_msg))))
return 0;
- memcpy(s->si2t_msg, si, MIN(msgb_l3len(msg), sizeof(s->si2t_msg)));
-
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2ter\n");
- /* Neighbor Cell Description 2 */
- s->nb_multi_rep_si2ter = (si->ext_bcch_frequency_list[0] >> 6) & 3;
- s->nb_ba_ind_si2ter = (si->ext_bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->settings, s->freq,
- si->ext_bcch_frequency_list,
- sizeof(si->ext_bcch_frequency_list), 0x8e,
- FREQ_TYPE_NCELL_2ter);
+ gsm48_decode_sysinfo2ter(s, si, msgb_l3len(msg));
- s->si2ter = 1;
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 2ter\n");
return gsm48_new_sysinfo(ms, si->header.system_information);
}
@@ -2044,29 +1753,8 @@ static int gsm48_rr_rx_sysinfo3(struct osmocom_ms *ms, struct msgb *msg)
if (!memcmp(si, s->si3_msg, MIN(msgb_l3len(msg), sizeof(s->si3_msg))))
return 0;
- memcpy(s->si3_msg, si, MIN(msgb_l3len(msg), sizeof(s->si3_msg)));
-
- /* Cell Identity */
- s->cell_id = ntohs(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_bcch(s, &si->cell_options);
- /* 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 3 Rest Octets */
- if (payload_len >= 4)
- gsm48_decode_si3_rest(s, si->rest_octets, payload_len);
-
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 3 (mcc %s mnc %s "
- "lac 0x%04x)\n", gsm_print_mcc(s->mcc),
- gsm_print_mnc(s->mnc), s->lac);
- s->si3 = 1;
+ gsm48_decode_sysinfo3(s, si, msgb_l3len(msg));
if (cs->ccch_mode == CCCH_MODE_NONE) {
cs->ccch_mode = (s->ccch_conf == 1) ? CCCH_MODE_COMBINED :
@@ -2086,8 +1774,6 @@ static int gsm48_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->cellsel.si;
int payload_len = msgb_l3len(msg) - sizeof(*si);
- uint8_t *data = si->data;
- struct gsm48_chan_desc *cd;
if (!s) {
LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 4 "
@@ -2096,62 +1782,20 @@ static int gsm48_rr_rx_sysinfo4(struct osmocom_ms *ms, struct msgb *msg)
}
if (payload_len < 0) {
- short_read:
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 4 "
"message.\n");
return -EINVAL;
}
- if (!s->si1) {
- LOGP(DRR, LOGL_NOTICE, "Ignoring SYSTEM INFORMATION 4 "
- "until SI 1 is received.\n");
- return -EBUSY;
- }
-
if (!memcmp(si, s->si4_msg, MIN(msgb_l3len(msg), sizeof(s->si4_msg))))
return 0;
- memcpy(s->si4_msg, si, MIN(msgb_l3len(msg), sizeof(s->si4_msg)));
-
- /* 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 >= 1 && data[0] == GSM48_IE_CBCH_CHAN_DESC) {
- if (payload_len < 4)
- goto short_read;
- cd = (struct gsm48_chan_desc *) (data + 1);
- if (cd->h0.h) {
- s->h = 1;
- gsm48_decode_chan_h1(cd, &s->tsc, &s->maio, &s->hsn);
- } else {
- s->h = 0;
- gsm48_decode_chan_h0(cd, &s->tsc, &s->arfcn);
- }
- payload_len -= 4;
- data += 4;
- }
- /* CBCH Mobile Allocation */
- 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->freq, data + 2, si->data[1],
- s->hopping, &s->hopp_len, 1);
- payload_len -= 2 + data[1];
- data += 2 + data[1];
- }
- /* SI 4 Rest Octets */
- if (payload_len > 0)
- gsm48_decode_si4_rest(s, data, payload_len);
+
+ gsm48_decode_sysinfo4(s, si, msgb_l3len(msg));
LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 4 (mcc %s mnc %s "
"lac 0x%04x)\n", gsm_print_mcc(s->mcc),
gsm_print_mnc(s->mnc), s->lac);
- s->si4 = 1;
-
return gsm48_new_sysinfo(ms, si->header.system_information);
}
@@ -2177,17 +1821,10 @@ static int gsm48_rr_rx_sysinfo5(struct osmocom_ms *ms, struct msgb *msg)
if (!memcmp(si, s->si5_msg, MIN(msgb_l3len(msg), sizeof(s->si5_msg))))
return 0;
- memcpy(s->si5_msg, si, MIN(msgb_l3len(msg), sizeof(s->si5_msg)));
-
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 5\n");
- /* Neighbor Cell Description */
- s->nb_ext_ind_si5 = (si->bcch_frequency_list[0] >> 6) & 1;
- s->nb_ba_ind_si5 = (si->bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->settings, s->freq, si->bcch_frequency_list,
- sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5);
+ gsm48_decode_sysinfo5(s, si, msgb_l3len(msg));
- s->si5 = 1;
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 5\n");
return gsm48_new_sysinfo(ms, si->system_information);
}
@@ -2212,20 +1849,13 @@ static int gsm48_rr_rx_sysinfo5bis(struct osmocom_ms *ms, struct msgb *msg)
return -EINVAL;
}
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 5bis\n");
-
if (!memcmp(si, s->si5b_msg, MIN(msgb_l3len(msg),
sizeof(s->si5b_msg))))
return 0;
- memcpy(s->si5b_msg, si, MIN(msgb_l3len(msg), sizeof(s->si5b_msg)));
- /* Neighbor Cell Description */
- s->nb_ext_ind_si5bis = (si->bcch_frequency_list[0] >> 6) & 1;
- s->nb_ba_ind_si5bis = (si->bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->settings, s->freq, si->bcch_frequency_list,
- sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5bis);
+ gsm48_decode_sysinfo5bis(s, si, msgb_l3len(msg));
- s->si5bis = 1;
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 5bis\n");
return gsm48_new_sysinfo(ms, si->system_information);
}
@@ -2250,20 +1880,13 @@ static int gsm48_rr_rx_sysinfo5ter(struct osmocom_ms *ms, struct msgb *msg)
return -EINVAL;
}
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 5ter\n");
-
if (!memcmp(si, s->si5t_msg, MIN(msgb_l3len(msg),
sizeof(s->si5t_msg))))
return 0;
- memcpy(s->si5t_msg, si, MIN(msgb_l3len(msg), sizeof(s->si5t_msg)));
- /* Neighbor Cell Description */
- s->nb_multi_rep_si5ter = (si->bcch_frequency_list[0] >> 6) & 3;
- s->nb_ba_ind_si5ter = (si->bcch_frequency_list[0] >> 5) & 1;
- decode_freq_list(&ms->settings, s->freq, si->bcch_frequency_list,
- sizeof(si->bcch_frequency_list), 0x8e, FREQ_TYPE_REP_5ter);
+ gsm48_decode_sysinfo5ter(s, si, msgb_l3len(msg));
- s->si5ter = 1;
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 5ter\n");
return gsm48_new_sysinfo(ms, si->system_information);
}
@@ -2291,22 +1914,8 @@ static int gsm48_rr_rx_sysinfo6(struct osmocom_ms *ms, struct msgb *msg)
if (!memcmp(si, s->si6_msg, MIN(msgb_l3len(msg), sizeof(s->si6_msg))))
return 0;
- memcpy(s->si6_msg, si, MIN(msgb_l3len(msg), sizeof(s->si6_msg)));
-
- /* Cell Identity */
- if (s->si6 && s->cell_id != ntohs(si->cell_identity))
- LOGP(DRR, LOGL_INFO, "Cell ID on SI 6 differs from previous "
- "read.\n");
- s->cell_id = ntohs(si->cell_identity);
- /* LAI */
- gsm48_decode_lai(&si->lai, &s->mcc, &s->mnc, &s->lac);
- /* Cell Options (SACCH) */
- gsm48_decode_cellopt_sacch(s, &si->cell_options);
- /* NCC Permitted */
- s->nb_ncc_permitted_si6 = si->ncc_permitted;
- /* SI 6 Rest Octets */
- if (payload_len >= 4)
- gsm48_decode_si6_rest(s, si->rest_octets, payload_len);
+
+ gsm48_decode_sysinfo6(s, si, msgb_l3len(msg));
LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 6 (mcc %s mnc %s "
"lac 0x%04x SACCH-timeout %d)\n", gsm_print_mcc(s->mcc),
@@ -2314,7 +1923,6 @@ static int gsm48_rr_rx_sysinfo6(struct osmocom_ms *ms, struct msgb *msg)
meas->rl_fail = meas->s = s->sacch_radio_link_timeout;
LOGP(DRR, LOGL_INFO, "using (new) SACCH timeout %d\n", meas->rl_fail);
- s->si6 = 1;
return gsm48_new_sysinfo(ms, si->system_information);
}
diff --git a/src/host/layer23/src/mobile/sysinfo.c b/src/host/layer23/src/mobile/sysinfo.c
index 2a125626..a4522ee8 100644
--- a/src/host/layer23/src/mobile/sysinfo.c
+++ b/src/host/layer23/src/mobile/sysinfo.c
@@ -22,9 +22,20 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
+#include <arpa/inet.h>
+
+#include <osmocore/bitvec.h>
#include <osmocom/bb/common/osmocom_data.h>
#include <osmocom/bb/common/networks.h>
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/mobile/sysinfo.h>
+
+#define MIN(a, b) ((a < b) ? a : b)
+
+/*
+ * dumping
+ */
int gsm48_sysinfo_dump(struct gsm48_sysinfo *s, uint16_t arfcn,
void (*print)(void *, const char *, ...), void *priv)
@@ -257,3 +268,505 @@ int gsm48_sysinfo_dump(struct gsm48_sysinfo *s, uint16_t arfcn,
return 0;
}
+/*
+ * decoding
+ */
+
+int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc,
+ uint16_t *mnc, uint16_t *lac)
+{
+ *mcc = ((lai->digits[0] & 0x0f) << 8)
+ | (lai->digits[0] & 0xf0)
+ | (lai->digits[1] & 0x0f);
+ *mnc = ((lai->digits[2] & 0x0f) << 8)
+ | (lai->digits[2] & 0xf0)
+ | ((lai->digits[1] & 0xf0) >> 4);
+ *lac = ntohs(lai->lac);
+
+ return 0;
+}
+
+int gsm48_decode_chan_h0(struct gsm48_chan_desc *cd, uint8_t *tsc,
+ uint16_t *arfcn)
+{
+ *tsc = cd->h0.tsc;
+ *arfcn = cd->h0.arfcn_low | (cd->h0.arfcn_high << 8);
+
+ return 0;
+}
+
+int gsm48_decode_chan_h1(struct gsm48_chan_desc *cd, uint8_t *tsc,
+ uint8_t *maio, uint8_t *hsn)
+{
+ *tsc = cd->h1.tsc;
+ *maio = cd->h1.maio_low | (cd->h1.maio_high << 2);
+ *hsn = cd->h1.hsn;
+
+ return 0;
+}
+
+/* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */
+static int decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd,
+ uint8_t len, uint8_t mask, uint8_t frqt)
+{
+#if 0
+ /* only Bit map 0 format for P-GSM */
+ if ((cd[0] & 0xc0 & mask) != 0x00 &&
+ (set->p_gsm && !set->e_gsm && !set->r_gsm && !set->dcs))
+ return 0;
+#endif
+
+ return gsm48_decode_freq_list(f, cd, len, mask, frqt);
+}
+
+/* decode "Cell Selection Parameters" (10.5.2.4) */
+static int gsm48_decode_cell_sel_param(struct gsm48_sysinfo *s,
+ struct gsm48_cell_sel_par *cs)
+{
+#ifdef TODO
+ convert ms_txpwr_max_ccch dependant on the current frequenc and support
+ to the right powe level
+#endif
+ s->ms_txpwr_max_cch = cs->ms_txpwr_max_ccch;
+ s->cell_resel_hyst_db = cs->cell_resel_hyst * 2;
+ s->rxlev_acc_min_db = cs->rxlev_acc_min - 110;
+ s->neci = cs->neci;
+ s->acs = cs->acs;
+
+ return 0;
+}
+
+/* decode "Cell Options (BCCH)" (10.5.2.3) */
+static int gsm48_decode_cellopt_bcch(struct gsm48_sysinfo *s,
+ struct gsm48_cell_options *co)
+{
+ s->bcch_radio_link_timeout = (co->radio_link_timeout + 1) * 4;
+ s->bcch_dtx = co->dtx;
+ s->bcch_pwrc = co->pwrc;
+
+ return 0;
+}
+
+/* decode "Cell Options (SACCH)" (10.5.2.3a) */
+static int gsm48_decode_cellopt_sacch(struct gsm48_sysinfo *s,
+ struct gsm48_cell_options *co)
+{
+ s->sacch_radio_link_timeout = (co->radio_link_timeout + 1) * 4;
+ s->sacch_dtx = co->dtx;
+ s->sacch_pwrc = co->pwrc;
+
+ return 0;
+}
+
+/* decode "Control Channel Description" (10.5.2.11) */
+static int gsm48_decode_ccd(struct gsm48_sysinfo *s,
+ struct gsm48_control_channel_descr *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 */
+
+ return 0;
+}
+
+/* decode "Mobile Allocation" (10.5.2.21) */
+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;
+ uint16_t f[len << 3];
+
+ /* not more than 64 hopping indexes allowed in IE */
+ if (len > 8)
+ return -EINVAL;
+
+ /* tabula rasa */
+ *hopp_len = 0;
+ if (si4) {
+ for (i = 0; i < 1024; i++)
+ freq[i].mask &= ~FREQ_TYPE_HOPP;
+ }
+
+ /* generating list of all frequencies (1..1023,0) */
+ for (i = 1; i <= 1024; i++) {
+ 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;
+ if (j == (len << 3))
+ break;
+ }
+ }
+
+ /* fill hopping table with frequency index given by IE
+ * and set hopping type bits
+ */
+ for (i = 0; i < (len << 3); i++) {
+ /* if bit is set, this frequency index is used for hopping */
+ if ((ma[len - 1 - (i >> 3)] & (1 << (i & 7)))) {
+ LOGP(DRR, LOGL_INFO, "Hopping ARFCN: %d (bit %d)\n",
+ i, f[i]);
+ /* index higher than entries in list ? */
+ if (i >= j) {
+ LOGP(DRR, LOGL_NOTICE, "Mobile Allocation "
+ "hopping index %d exceeds maximum "
+ "number of cell frequencies. (%d)\n",
+ i + 1, j);
+ break;
+ }
+ hopping[(*hopp_len)++] = f[i];
+ if (si4)
+ freq[f[i]].mask |= FREQ_TYPE_HOPP;
+ }
+ }
+
+ return 0;
+}
+
+/* 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_control *rc)
+{
+ s->reest_denied = rc->re;
+ s->cell_barr = rc->cell_bar;
+ s->tx_integer = gsm48_tx_integer[rc->tx_integer];
+ s->max_retrans = gsm48_max_retrans[rc->max_trans];
+ s->class_barr = (rc->t2 << 8) | rc->t3;
+
+ return 0;
+}
+static int gsm48_decode_rach_ctl_neigh(struct gsm48_sysinfo *s,
+ struct gsm48_rach_control *rc)
+{
+ s->nb_reest_denied = rc->re;
+ s->nb_cell_barr = rc->cell_bar;
+ s->nb_tx_integer = gsm48_tx_integer[rc->tx_integer];
+ s->nb_max_retrans = gsm48_max_retrans[rc->max_trans];
+ s->nb_class_barr = (rc->t2 << 8) | rc->t3;
+
+ 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)
+{
+ return 0;
+}
+
+/* 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)
+{
+ struct bitvec bv;
+
+ memset(&bv, 0, sizeof(bv));
+ bv.data_len = len;
+ bv.data = si;
+
+ /* Optional Selection Parameters */
+ if (bitvec_get_bit_high(&bv) == H) {
+ s->sp = 1;
+ s->sp_cbq = bitvec_get_uint(&bv, 1);
+ s->sp_cro = bitvec_get_uint(&bv, 6);
+ s->sp_to = bitvec_get_uint(&bv, 3);
+ s->sp_pt = bitvec_get_uint(&bv, 5);
+ }
+ /* Optional Power Offset */
+ if (bitvec_get_bit_high(&bv) == H) {
+ s->po = 1;
+ s->po_value = bitvec_get_uint(&bv, 3);
+ }
+ /* System Onformation 2ter Indicator */
+ if (bitvec_get_bit_high(&bv) == H)
+ s->si2ter_ind = 1;
+ /* Early Classark Sending Control */
+ if (bitvec_get_bit_high(&bv) == H)
+ s->ecsm = 1;
+ /* Scheduling if and where */
+ if (bitvec_get_bit_high(&bv) == H) {
+ s->sched = 1;
+ s->sched_where = bitvec_get_uint(&bv, 3);
+ }
+ /* GPRS Indicator */
+ s->gi_ra_colour = bitvec_get_uint(&bv, 3);
+ s->gi_si13_pos = bitvec_get_uint(&bv, 1);
+ return 0;
+}
+
+/* decode "SI 4 Rest Octets" (10.5.2.35) */
+static int gsm48_decode_si4_rest(struct gsm48_sysinfo *s, uint8_t *si,
+ uint8_t len)
+{
+ return 0;
+}
+
+/* decode "SI 6 Rest Octets" (10.5.2.35a) */
+static int gsm48_decode_si6_rest(struct gsm48_sysinfo *s, uint8_t *si,
+ uint8_t len)
+{
+ return 0;
+}
+
+int gsm48_decode_sysinfo1(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_1 *si, int len)
+{
+ int payload_len = len - sizeof(*si);
+
+ memcpy(s->si1_msg, si, MIN(len, sizeof(s->si1_msg)));
+
+ /* Cell Channel Description */
+ decode_freq_list(s->freq, si->cell_channel_description,
+ sizeof(si->cell_channel_description), 0xce, FREQ_TYPE_SERV);
+ /* RACH Control Parameter */
+ gsm48_decode_rach_ctl_param(s, &si->rach_control);
+ /* SI 1 Rest Octets */
+ if (payload_len)
+ gsm48_decode_si1_rest(s, si->rest_octets, payload_len);
+
+ if (!s->si1 && s->si4) {
+ s->si1 = 1;
+ LOGP(DRR, LOGL_NOTICE, "Now decoding previously received "
+ "SYSTEM INFORMATION 4\n");
+ gsm48_decode_sysinfo4(s,
+ (struct gsm48_system_information_type_4 *) s->si4_msg,
+ sizeof(s->si4_msg));
+
+ return -EBUSY;
+ }
+
+ s->si1 = 1;
+
+ return 0;
+}
+
+int gsm48_decode_sysinfo2(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_2 *si, int len)
+{
+ memcpy(s->si2_msg, si, MIN(len, sizeof(s->si2_msg)));
+
+ /* Neighbor Cell Description */
+ s->nb_ext_ind_si2 = (si->bcch_frequency_list[0] >> 6) & 1;
+ s->nb_ba_ind_si2 = (si->bcch_frequency_list[0] >> 5) & 1;
+ decode_freq_list(s->freq, si->bcch_frequency_list,
+ sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_NCELL_2);
+ /* NCC Permitted */
+ s->nb_ncc_permitted_si2 = si->ncc_permitted;
+ /* RACH Control Parameter */
+ gsm48_decode_rach_ctl_neigh(s, &si->rach_control);
+
+ s->si2 = 1;
+
+ return 0;
+}
+
+int gsm48_decode_sysinfo2bis(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_2bis *si, int len)
+{
+ memcpy(s->si2b_msg, si, MIN(len, sizeof(s->si2b_msg)));
+
+ /* Neighbor Cell Description */
+ s->nb_ext_ind_si2bis = (si->bcch_frequency_list[0] >> 6) & 1;
+ s->nb_ba_ind_si2bis = (si->bcch_frequency_list[0] >> 5) & 1;
+ decode_freq_list(s->freq, si->bcch_frequency_list,
+ sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_NCELL_2bis);
+ /* RACH Control Parameter */
+ gsm48_decode_rach_ctl_neigh(s, &si->rach_control);
+
+ s->si2bis = 1;
+
+ return 0;
+}
+
+int gsm48_decode_sysinfo2ter(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_2ter *si, int len)
+{
+ memcpy(s->si2t_msg, si, MIN(len, sizeof(s->si2t_msg)));
+
+ /* Neighbor Cell Description 2 */
+ s->nb_multi_rep_si2ter = (si->ext_bcch_frequency_list[0] >> 6) & 3;
+ s->nb_ba_ind_si2ter = (si->ext_bcch_frequency_list[0] >> 5) & 1;
+ decode_freq_list(s->freq, si->ext_bcch_frequency_list,
+ sizeof(si->ext_bcch_frequency_list), 0x8e,
+ FREQ_TYPE_NCELL_2ter);
+
+ s->si2ter = 1;
+
+ return 0;
+}
+
+int gsm48_decode_sysinfo3(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_3 *si, int len)
+{
+ int payload_len = len - sizeof(*si);
+
+ memcpy(s->si3_msg, si, MIN(len, sizeof(s->si3_msg)));
+
+ /* Cell Identity */
+ s->cell_id = ntohs(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_bcch(s, &si->cell_options);
+ /* 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 3 Rest Octets */
+ if (payload_len >= 4)
+ gsm48_decode_si3_rest(s, si->rest_octets, payload_len);
+
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 3 (mcc %s mnc %s "
+ "lac 0x%04x)\n", gsm_print_mcc(s->mcc),
+ gsm_print_mnc(s->mnc), s->lac);
+
+ s->si3 = 1;
+
+ return 0;
+}
+
+int gsm48_decode_sysinfo4(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_4 *si, int len)
+{
+ int payload_len = len - sizeof(*si);
+
+ uint8_t *data = si->data;
+ struct gsm48_chan_desc *cd;
+
+ memcpy(s->si4_msg, si, MIN(len, sizeof(s->si4_msg)));
+
+ if (!s->si1) {
+ LOGP(DRR, LOGL_NOTICE, "Ignoring SYSTEM INFORMATION 4 "
+ "until SI 1 is received.\n");
+ s->si4 = 1;
+ return -EBUSY;
+ }
+ /* 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 >= 1 && data[0] == GSM48_IE_CBCH_CHAN_DESC) {
+ if (payload_len < 4) {
+short_read:
+ LOGP(DRR, LOGL_NOTICE, "Short read!\n");
+ return -EIO;
+ }
+ cd = (struct gsm48_chan_desc *) (data + 1);
+ if (cd->h0.h) {
+ s->h = 1;
+ gsm48_decode_chan_h1(cd, &s->tsc, &s->maio, &s->hsn);
+ } else {
+ s->h = 0;
+ gsm48_decode_chan_h0(cd, &s->tsc, &s->arfcn);
+ }
+ payload_len -= 4;
+ data += 4;
+ }
+ /* CBCH Mobile Allocation */
+ 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->freq, data + 2, si->data[1],
+ s->hopping, &s->hopp_len, 1);
+ payload_len -= 2 + data[1];
+ data += 2 + data[1];
+ }
+ /* SI 4 Rest Octets */
+ if (payload_len > 0)
+ gsm48_decode_si4_rest(s, data, payload_len);
+
+ s->si4 = 1;
+
+ return 0;
+}
+
+int gsm48_decode_sysinfo5(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_5 *si, int len)
+{
+ memcpy(s->si5_msg, si, MIN(len, sizeof(s->si5_msg)));
+
+ /* Neighbor Cell Description */
+ s->nb_ext_ind_si5 = (si->bcch_frequency_list[0] >> 6) & 1;
+ s->nb_ba_ind_si5 = (si->bcch_frequency_list[0] >> 5) & 1;
+ decode_freq_list(s->freq, si->bcch_frequency_list,
+ sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5);
+
+ s->si5 = 1;
+
+ return 0;
+}
+
+int gsm48_decode_sysinfo5bis(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_5bis *si, int len)
+{
+ memcpy(s->si5b_msg, si, MIN(len, sizeof(s->si5b_msg)));
+
+ /* Neighbor Cell Description */
+ s->nb_ext_ind_si5bis = (si->bcch_frequency_list[0] >> 6) & 1;
+ s->nb_ba_ind_si5bis = (si->bcch_frequency_list[0] >> 5) & 1;
+ decode_freq_list(s->freq, si->bcch_frequency_list,
+ sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5bis);
+
+ s->si5bis = 1;
+
+ return 0;
+}
+
+int gsm48_decode_sysinfo5ter(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_5ter *si, int len)
+{
+ memcpy(s->si5t_msg, si, MIN(len, sizeof(s->si5t_msg)));
+
+ /* Neighbor Cell Description */
+ s->nb_multi_rep_si5ter = (si->bcch_frequency_list[0] >> 6) & 3;
+ s->nb_ba_ind_si5ter = (si->bcch_frequency_list[0] >> 5) & 1;
+ decode_freq_list(s->freq, si->bcch_frequency_list,
+ sizeof(si->bcch_frequency_list), 0x8e, FREQ_TYPE_REP_5ter);
+
+ s->si5ter = 1;
+
+ return 0;
+}
+
+int gsm48_decode_sysinfo6(struct gsm48_sysinfo *s,
+ struct gsm48_system_information_type_6 *si, int len)
+{
+ int payload_len = len - sizeof(*si);
+
+ memcpy(s->si6_msg, si, MIN(len, sizeof(s->si6_msg)));
+
+ /* Cell Identity */
+ if (s->si6 && s->cell_id != ntohs(si->cell_identity))
+ LOGP(DRR, LOGL_INFO, "Cell ID on SI 6 differs from previous "
+ "read.\n");
+ s->cell_id = ntohs(si->cell_identity);
+ /* LAI */
+ gsm48_decode_lai(&si->lai, &s->mcc, &s->mnc, &s->lac);
+ /* Cell Options (SACCH) */
+ gsm48_decode_cellopt_sacch(s, &si->cell_options);
+ /* NCC Permitted */
+ s->nb_ncc_permitted_si6 = si->ncc_permitted;
+ /* SI 6 Rest Octets */
+ if (payload_len >= 4)
+ gsm48_decode_si6_rest(s, si->rest_octets, payload_len);
+
+ s->si6 = 1;
+
+ return 0;
+}
+