*
*/
+/* Very short description of some of the procedures:
+ *
+ * A radio ressource request causes sendig a channel request on RACH.
+ * After receiving of an immediate assignment the link will be establised.
+ * After the link is established, the dedicated mode is entered and confirmed.
+ *
+ * A Paging request also triggers the channel request as above...
+ * After the link is established, the dedicated mode is entered and indicated.
+ *
+ * During dedicated mode, messages are transferred.
+ *
+ * When an assignment command or a handover command is received, the current
+ * link is released. After release, the new channel is activated and the
+ * link is established again. After link is establised, pending messages from
+ * radio ressource are sent.
+ *
+ * When the assignment or handover fails, the old channel is activate and the
+ * link is established again. Also pending messages are sent.
+ *
+ */
+
/*
* state transition
*/
-char *rr_state_names[] = {
+const char *rr_state_names[] = {
"IDLE",
"CONN PEND",
"DEDICATED",
rr->state = state;
}
+/*
+ * messages
+ */
+
+/* allocate GSM 04.08 radio ressource message (RR to L2) */
+static struct msgb *gsm48_rr_msgb_alloc(void)
+{
+ struct msgb *msg;
+
+ msg = msgb_alloc_headroom(GSM48_RR_ALLOC_SIZE, GSM48_RR_ALLOC_HEADROOM,
+ "GSM 04.08 RR");
+ if (!msg)
+ return NULL;
+
+ return msg;
+}
+
+/* queue message L2 -> RR */
+int gsm48_rr_upmsg(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+
+ msgb_enqueue(&rr->up_queue, msg);
+}
+
/*
* timers handling
*/
mmh = (struct gsm_mm_hdr *)msg->data;
mmh->msg_type RR_REL_IND;
mmh->cause = GSM_MM_CAUSE_RA_FAILURE;
- rr_rcvmsg(ms, msg);
+ gsm48_mm_upmsg(ms, msg);
}
new_rr_state(rr, GSM_RRSTATE_IDLE);
static int gsm_rr_tx_rr_status(struct osmocom_ms *ms, uint8_t cause)
{
struct gsm_rrlayer *rr = ms->rrlayer;
- struct msgb *msg = gsm48_rr_msgb_alloc();
+ struct msgb *msg;
struct gsm48_hdr *gh;
struct gsm48_rr_status *st;
+ msg = gsm48_rr_msgb_alloc();
if (!msg)
return -ENOMEM;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
{
struct gsm_rrlayer *rr = ms->rrlayer;
struct gsm_subscriber *subcr = ms->subscr;
- struct msgb *msg = gsm48_rr_msgb_alloc();
+ struct msgb *msg;
struct gsm48_hdr *gh;
u_int8_t buf[11], *ie;
+ msg = gsm48_rr_msgb_alloc();
if (!msg)
return -ENOMEM;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
* classmark
*/
-/* encode classmark 3 */
-#define ADD_BIT(a) \
-{ \
- if (bit-- == 0) { \
- bit = 7; \
- buf[byte] = 0; \
- } \
- buf[byte] |= ((a) << bit); \
- if (bit == 0) \
- byte++; \
-}
+/* Encode "Classmark 3" (10.5.2.20) */
static int gsm_rr_enc_cm3(struct osmocom_sm *ms, uint8_t *buf, uint8_t *len)
{
struct gsm_support *sup = ms->support;
- uint8_t bit = 0, byte = 0;
+ struct bitvec bv;
+
+ memset(&bv, 0, sizeof(bv));
+ bv.data = data;
+ bv.data_len = 12;
/* spare bit */
- ADD_BIT(0)
+ bitvec_set_bit(&bv, 0);
/* band 3 supported */
if (sup->dcs_1800)
- ADD_BIT(1)
+ bitvec_set_bit(&bv, ONE);
else
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
/* band 2 supported */
if (sup->e_gsm || sup->r_gsm)
- ADD_BIT(1)
+ bitvec_set_bit(&bv, ONE);
else
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
/* band 1 supported */
if (sup->p_gsm && !(sup->e_gsm || sup->r_gsm))
- ADD_BIT(1)
+ bitvec_set_bit(&bv, ONE);
else
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
/* a5 bits */
if (sup->a5_7)
- ADD_BIT(1)
+ bitvec_set_bit(&bv, ONE);
else
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
if (sup->a5_6)
- ADD_BIT(1)
+ bitvec_set_bit(&bv, ONE);
else
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
if (sup->a5_5)
- ADD_BIT(1)
+ bitvec_set_bit(&bv, ONE);
else
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
if (sup->a5_4)
- ADD_BIT(1)
+ bitvec_set_bit(&bv, ONE);
else
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
/* radio capability */
if (sup->dcs_1800 && !sup->p_gsm && !(sup->e_gsm || sup->r_gsm)) {
/* dcs only */
- ADD_BIT(0)
- ADD_BIT(0)
- ADD_BIT(0)
- ADD_BIT(0)
- ADD_BIT((sup->dcs_capa >> 3) & 1)
- ADD_BIT((sup->dcs_capa >> 2) & 1)
- ADD_BIT((sup->dcs_capa >> 1) & 1)
- ADD_BIT(sup->dcs_capa & 1)
+ bitvec_set_uint(&bv, 0, 4);
+ bitvec_set_uint(&bv, sup->dcs_capa, 4);
} else
if (sup->dcs_1800 && (sup->p_gsm || (sup->e_gsm || sup->r_gsm))) {
/* dcs */
- ADD_BIT((sup->dcs_capa >> 3) & 1)
- ADD_BIT((sup->dcs_capa >> 2) & 1)
- ADD_BIT((sup->dcs_capa >> 1) & 1)
- ADD_BIT(sup->dcs_capa & 1)
+ bitvec_set_uint(&bv, sup->dcs_capa, 4);
/* low band */
- ADD_BIT((sup->low_capa >> 3) & 1)
- ADD_BIT((sup->low_capa >> 2) & 1)
- ADD_BIT((sup->low_capa >> 1) & 1)
- ADD_BIT(sup->low_capa & 1)
+ bitvec_set_uint(&bv, sup->low_capa, 4);
} else {
/* low band only */
- ADD_BIT(0)
- ADD_BIT(0)
- ADD_BIT(0)
- ADD_BIT(0)
- ADD_BIT((sup->low_capa >> 3) & 1)
- ADD_BIT((sup->low_capa >> 2) & 1)
- ADD_BIT((sup->low_capa >> 1) & 1)
- ADD_BIT(sup->low_capa & 1)
+ bitvec_set_uint(&bv, 0, 4);
+ bitvec_set_uint(&bv, sup->low_capa, 4);
}
/* r support */
if (sup->r_gsm) {
- ADD_BIT(1)
- ADD_BIT((sup->r_capa >> 2) & 1)
- ADD_BIT((sup->r_capa >> 1) & 1)
- ADD_BIT(sup->r_capa & 1)
+ bitvec_set_bit(&bv, ONE);
+ bitvec_set_uint(&bv, sup->r_capa, 3);
} else {
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
}
/* multi slot support */
if (sup->ms_sup) {
- ADD_BIT(1)
- ADD_BIT((sup->ms_capa >> 4) & 1)
- ADD_BIT((sup->ms_capa >> 3) & 1)
- ADD_BIT((sup->ms_capa >> 2) & 1)
- ADD_BIT((sup->ms_capa >> 1) & 1)
- ADD_BIT(sup->ms_capa & 1)
+ bitvec_set_bit(&bv, ONE);
+ bitvec_set_uint(&bv, sup->ms_capa, 5);
} else {
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
}
/* ucs2 treatment */
if (sup->ucs2_treat) {
- ADD_BIT(1)
+ bitvec_set_bit(&bv, ONE);
} else {
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
}
/* support extended measurements */
if (sup->ext_meas) {
- ADD_BIT(1)
+ bitvec_set_bit(&bv, ONE);
} else {
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
}
/* support measurement capability */
if (sup->meas_cap) {
- ADD_BIT(1)
- ADD_BIT((sup->sms_val >> 3) & 1)
- ADD_BIT((sup->sms_val >> 2) & 1)
- ADD_BIT((sup->sms_val >> 1) & 1)
- ADD_BIT(sup->sms_val & 1)
- ADD_BIT((sup->sm_val >> 3) & 1)
- ADD_BIT((sup->sm_val >> 2) & 1)
- ADD_BIT((sup->sm_val >> 1) & 1)
- ADD_BIT(sup->sm_val & 1)
+ bitvec_set_bit(&bv, ONE);
+ bitvec_set_uint(&bv, sup->sms_val, 4);
+ bitvec_set_uint(&bv, sup->sm_val, 4);
} else {
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
}
/* positioning method capability */
if (sup->loc_serv) {
- ADD_BIT(1)
- ADD_BIT(sup->e_otd_ass == 1)
- ADD_BIT(sup->e_otd_based == 1)
- ADD_BIT(sup->gps_ass == 1)
- ADD_BIT(sup->gps_based == 1)
- ADD_BIT(sup->gps_conv == 1)
+ bitvec_set_bit(&bv, ONE);
+ bitvec_set_bit(&bv, sup->e_otd_ass == 1);
+ bitvec_set_bit(&bv, sup->e_otd_based == 1);
+ bitvec_set_bit(&bv, sup->gps_ass == 1);
+ bitvec_set_bit(&bv, sup->gps_based == 1);
+ bitvec_set_bit(&bv, sup->gps_conv == 1);
} else {
- ADD_BIT(0)
+ bitvec_set_bit(&bv, ZERO);
}
/* partitial bytes will be completed */
- if (bit)
- byte++;
- *len = byte;
+ *len = (bv.cur_bit + 7) >> 3;
+ bitvec_spare_padding(&bv, (*len * 8) - 1);
return 0;
}
{
struct gsm_rrlayer *rr = ms->rrlayer;
struct gsm_support *sup = ms->support;
- struct msgb *msg = gsm48_rr_msgb_alloc();
+ struct msgb *msg;
struct gsm48_hdr *gh;
struct gsm48_cm_change *cc;
int len;
uint8_t buf[14];
+ msg = gsm48_rr_msgb_alloc();
if (!msg)
return -ENOMEM;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|| sup->loc_serv) {
cm->cm2.cm3 = 1;
buf[0] = GSM48_IE_CLASSMARK2;
- gsm_rr_enc_cm3(ms, buf + 1, &buf[0]);
+ gsm_rr_enc_cm3(ms, buf + 2, &buf[1]);
}
return rslms_data_req(ms, msg, 0);
mmh = (struct gsm_mm_hdr *)msg->data;
mmh->msg_type RR_REL_IND;
mmh->cause = GSM_MM_CAUSE_UNDEFINED;
- rr_rcvmsg(ms, msg);
+ gsm48_mm_upmsg(ms, msg);
new_rr_state(rr, GSM_RRSTATE_IDLE);
return -EINVAL;
}
static int gsm_rr_rand_acc_cnf(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm_rrlayer *rr = ms->rrlayer;
- struct msgb *newmsg;
+ struct msgb *nmsg;
int s;
if (!rr->n_chan_req) {
s = 115;
/* resend chan_req */
- newmsg = msgb_alloc_headroom(20, 16, "CHAN_REQ");
- if (!newmsg)
+ nmsg = msgb_alloc_headroom(20, 16, "CHAN_REQ");
+ if (!nmsg)
return -ENOMEM;
- *msgb_put(newmsg, 1) = rr->chan_req;
- *msgb_put(newmsg, 1) = (random() % ms->si.tx_integer) + s; /* delay */
+ *msgb_put(nmsg, 1) = rr->chan_req;
+ *msgb_put(nmsg, 1) = (random() % ms->si.tx_integer) + s; /* delay */
rr->cr_hist[3] = rr->cr_hist[2];
rr->cr_hist[2] = rr->cr_hist[1];
rr->cr_hist[1] = chan_req;
- return rslms_tx_rll_req_l3(ms, RSL_MT_RAND_ACC_REQ, chan_nr, 0, newmsg);
+ return rslms_tx_rll_req_l3(ms, RSL_MT_RAND_ACC_REQ, chan_nr, 0, nmsg);
}
/*
- * paging
+ * system information
*/
-/* paging channel request */
-static int gsm_rr_chan2cause[4] = {
- RR_EST_CAUSE_ANS_PAG_ANY,
- RR_EST_CAUSE_ANS_PAG_SDCCH,
- RR_EST_CAUSE_ANS_PAG_TCH_F,
- RR_EST_CAUSE_ANS_PAG_TCH_ANY
-};
-
-/* given LV of mobile identity is checked agains ms */
-static int gsm_match_mi(struct osmocom_ms *ms, u_int8_t mi)
-{
- char imsi[16];
- u_int32_t tmsi;
-
- if (mi[0] < 1)
- return 0;
- mi_type = mi[1] & GSM_MI_TYPE_MASK;
- switch (mi_type) {
- case GSM_MI_TYPE_TMSI:
- if (mi[0] < 5)
- return;
- memcpy(&tmsi, mi+2, 4);
- if (ms->subscr.tmsi == ntohl(tmsi)
- && ms->subscr.tmsi_valid)
- return 1;
- break;
- case GSM_MI_TYPE_IMSI:
- gsm48_mi_to_string(imsi, sizeof(imsi), mi + 1, mi[0]);
- if (!strcmp(imsi, ms->subscr.imsi))
- return 1;
- break;
- default:
- DEBUGP(DRR, "paging with unsupported MI type %d.\n", mi_type);
- }
-
- return 0;
-}
-
-/* paging request 1 message */
-static int gsm_rr_rx_pag_req_1(struct osmocom_ms *ms, struct msgb *msg)
+/* 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, uint8_t frqt)
{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm48_rr_paging1 *pa = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*pa);
- int chan_first, chan_second;
- uint8_t mi;
-
- /* 3.3.1.1.2: ignore paging while establishing */
- if (rr->state != GSM_RRSTATE_IDLE)
- return 0;
-
- if (payload_len < 2) {
- short:
- DEBUGP(DRR, "Short read of paging request 1 message .\n");
- return -EINVAL;
- }
+ int i;
- /* channel needed */
- chan_first = pa->cneed1;
- chan_second = pa->cneed2;
- /* first MI */
- mi = pa->data + 1;
- if (payload_len < mi[0] + 1)
- goto short;
- if (gsm_match_mi(ms, mi) > 0)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_first]);
- /* second MI */
- payload_len -= mi[0] + 1;
- mi = pa->data + mi[0] + 1;
- if (payload_len < 2)
- return 0;
- if (mi[0] != GSM48_IE_MOBILE_ID)
- return 0;
- if (payload_len < mi[1] + 2)
- goto short;
- if (gsm_match_mi(ms, mi + 1) > 0)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_second]);
+ /* 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.
+ */
- return 0;
-}
+ /* tabula rasa */
+ for (i = 0; i < 1024; i++)
+ f[i].mask &= ~frqt;
-/* paging request 2 message */
-static int gsm_rr_rx_pag_req_2(struct osmocom_ms *ms, struct gsm_msgb *msg)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm48_rr_paging2 *pa = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*pa);
- u_int32_t tmsi;
- int chan_first, chan_second, chan_third;
+ /* 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].mask |= frqt;
- /* 3.3.1.1.2: ignore paging while establishing */
- if (rr->state != GSM_RRSTATE_IDLE)
return 0;
-
- if (payload_len < 0) {
- short:
- DEBUGP(DRR, "Short read of paging request 2 message .\n");
- return -EINVAL;
}
- /* channel needed */
- chan_first = pa->cneed1;
- chan_second = pa->cneed2;
- /* first MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi1)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_first]);
- /* second MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi2)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_second]);
- /* third MI */
- mi = pa->data;
- if (payload_len < 2)
- return 0;
- if (mi[0] != GSM48_IE_MOBILE_ID)
- return 0;
- if (payload_len < mi[1] + 2 + 1) /* must include "channel needed" */
- goto short;
- chan_third = mi[mi[1] + 2] & 0x03; /* channel needed */
- if (gsm_match_mi(ms, mi + 1) > 0)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_third]);
+ /* 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;
- 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;
-/* paging request 3 message */
-static int gsm_rr_rx_pag_req_3(struct osmocom_ms *ms, struct gsm_msgb *msg)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm48_rr_paging3 *pa = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*pa);
- u_int32_t tmsi;
- int chan_first, chan_second, chan_third, chan_fourth;
+ if (len < 2)
+ return -EINVAL;
+ memset(w, 0, sizeof(w));
+ if (r->f0)
+ f[0].mask |= frqt;
+ 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]].mask |= frqt;
+ if (w[2])
+ f[((w[1] - 512 + w[2] - 1) % 1023) + 1].mask |= frqt;
+ if (w[3])
+ f[((w[1] + w[3] - 1) % 1023) + 1].mask |= frqt;
+ if (w[4])
+ f[((w[1] - 512 + ((w[2] - 256 + w[4] - 1) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[5])
+ f[((w[1] + ((w[3] - 256 - w[5] - 1) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[6])
+ f[((w[1] - 512 + ((w[2] + w[6] - 1) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[7])
+ f[((w[1] + ((w[3] + w[7] - 1) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[8])
+ f[((w[1] - 512 + ((w[2] - 256 + ((w[4] - 128 + w[8] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[9])
+ f[((w[1] + ((w[3] - 256 + ((w[5] - 128 + w[9] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[10])
+ f[((w[1] - 512 + ((w[2] + ((w[6] - 128 + w[10] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[11])
+ f[((w[1] + ((w[3] + ((w[7] - 128 + w[11] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[12])
+ f[((w[1] - 512 + ((w[2] - 256 + ((w[4] + w[12] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[13])
+ f[((w[1] + ((w[3] - 256 + ((w[5] + w[13] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[14])
+ f[((w[1] - 512 + ((w[2] + ((w[6] + w[14] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[15])
+ f[((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
+ if (w[16])
+ f[((w[1] - 512 + ((w[2] - 256 + ((w[4] - 128 + ((w[8] - 64 + w[16] - 1) % 127)) % 255)) % 511)) % 1023) + 1].mask |= frqt;
- /* 3.3.1.1.2: ignore paging while establishing */
- if (rr->state != GSM_RRSTATE_IDLE)
return 0;
-
- if (payload_len < 0) { /* must include "channel needed", part of *pa */
- short:
- DEBUGP(DRR, "Short read of paging request 3 message .\n");
- return -EINVAL;
}
+ /* 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;
- /* channel needed */
- chan_first = pa->cneed1;
- chan_second = pa->cneed2;
- chan_third = pa->cneed3;
- chan_fourth = pa->cneed4;
- /* first MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi1)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_first]);
- /* second MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi2)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_second]);
- /* thrid MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi3)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_third]);
- /* fourth MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi4)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_fourth]);
-
- return 0;
-}
+ 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]].mask |= frqt;
+ if (w[1])
+ f[(w[0] + w[1]) % 1024].mask |= frqt;
+ if (w[2])
+ f[(w[0] + ((w[1] - 256 + w[2] - 1) % 511) + 1) % 1024].mask |= frqt;
+ if (w[3])
+ f[(w[0] + ((w[1] + w[3] - 1) % 511) + 1) % 1024].mask |= frqt;
+ if (w[4])
+ f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + w[4] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[5])
+ f[(w[0] + ((w[1] + ((w[3] - 128 + w[5] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[6])
+ f[(w[0] + ((w[1] - 256 + ((w[2] + w[6] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[7])
+ f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[8])
+ f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] - 64 + w[8] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[9])
+ f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] - 64 + w[9] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[10])
+ f[(w[0] + ((w[1] - 256 + ((w[2] + ((w[6] - 64 + w[10] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[11])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 64 + w[11] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[12])
+ f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] + w[12] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[13])
+ f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] + w[13] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[14])
+ f[(w[0] + ((w[1] - 256 + ((w[2] + ((w[6] + w[14] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ if (w[15])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
-/*
- * (immediate) assignment
- */
+ 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;
-/* match request reference agains request history */
-static int gsm_match_ra(struct osmocom_ms *ms, struct gsm48_req_ref *req)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- int i;
+ 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]].mask |= frqt;
+ if (w[1])
+ f[(w[0] + w[1]) % 1024].mask |= frqt;
+ if (w[2])
+ f[(w[0] + ((w[1] - 128 + w[2] - 1) % 255) + 1) % 1024].mask |= frqt;
+ if (w[3])
+ f[(w[0] + ((w[1] + w[3] - 1) % 255) + 1) % 1024].mask |= frqt;
+ if (w[4])
+ f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + w[4] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[5])
+ f[(w[0] + ((w[1] + ((w[3] - 64 + w[5] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[6])
+ f[(w[0] + ((w[1] - 128 + ((w[2] + w[6] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[7])
+ f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[8])
+ f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] - 32 + w[8] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[9])
+ f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] - 32 + w[9] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[10])
+ f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] - 32 + w[10] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[11])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 32 + w[11] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[12])
+ f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] + w[12] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[13])
+ f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] + w[13] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[14])
+ f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] + w[14] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ if (w[15])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
- for (i = 0; i < 3; i++) {
- if (rr->cr_hist[i] >= 0
- && ref->ra == rr->cr_hist[i]) {
- // todo: match timeslot
- return 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;
- return 0;
-}
-
-/* transmit assignment complete after establishing link */
-static int gsm_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct msgb *msg = gsm48_rr_msgb_alloc();
- struct gsm48_hdr *gh;
- struct gsm48_ass_cpl *ac;
+ 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]].mask |= frqt;
+ if (w[1])
+ f[(w[0] + w[1]) % 1024].mask |= frqt;
+ if (w[2])
+ f[(w[0] + ((w[1] - 64 + w[2] - 1) % 127) + 1) % 1024].mask |= frqt;
+ if (w[3])
+ f[(w[0] + ((w[1] + w[3] - 1) % 127) + 1) % 1024].mask |= frqt;
+ if (w[4])
+ f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + w[4] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[5])
+ f[(w[0] + ((w[1] + ((w[3] - 32 + w[5] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[6])
+ f[(w[0] + ((w[1] - 64 + ((w[2] + w[6] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[7])
+ f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[8])
+ f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + w[8] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[9])
+ f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + w[9] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[10])
+ f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + w[10] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[11])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + w[11] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[12])
+ f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + w[12] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[13])
+ f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] + w[13] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[14])
+ f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] + w[14] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ if (w[15])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ if (w[23])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] + ((w[15] - 8 + w[23] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ 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].mask |= frqt;
+ if (w[27])
+ f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + ((w[11] + w[27] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
+ 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].mask |= frqt;
- if (!msg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- ac = (struct gsm48_ass_cpl *) msgb_put(msg, sizeof(*ac));
+ 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;
- gh->proto = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_ASS_COMPL;
+ if (len < 3)
+ return -EINVAL;
+ orig = (r->orig_arfcn_hi << 9) || (r->orig_arfcn_mid << 1) || r->orig_arfcn_lo;
+ f[orig].mask |= frqt;
+ for (i = 1; 2 + (i >> 3) < len; i++)
+ if ((cd[2 + (i >> 3)] & (0x80 >> (i & 7))))
+ f[(orig + 1) % 1024].mask |= frqt;
- /* RR_CAUSE */
- ac->rr_cause = cause;
+ return 0;
+ }
- return rslms_data_req(ms, msg, 0);
}
-/* transmit failure to old link */
-static int gsm_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause)
+/* 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)
{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct msgb *msg = gsm48_rr_msgb_alloc();
- struct gsm48_hdr *gh;
- struct gsm48_ass_fail *ac;
-
- if (!msg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- af = (struct gsm48_ass_fail *) msgb_put(msg, sizeof(*af));
-
- gh->proto = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_ASS_COMPL;
+ s->ms_txpwr_max_ccch = 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;
+}
- /* RR_CAUSE */
- af->rr_cause = cause;
+/* 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 rslms_data_req(ms, msg, 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;
}
-/* receive immediate assignment */
-static int gsm_rr_rx_imm_ass(struct osmocom_ms *ms, struct gsm_msgb *msg)
+/* decode "Cell Channel Description" (10.5.2.11) */
+static int gsm48_decode_ccd(struct gsm48_sysinfo *s, struct gsm48_control_channel_desc *cc)
{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm48_imm_ass *ia = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*ia);
+ 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 */
+}
- /* 3.3.1.1.2: ignore assignment while idle */
- if (rr->state != GSM_RRSTATE_CONN_PEND || !rr->wait_assign)
- return 0;
+/* decode "Mobile Allocation" (10.5.2.21) */
+static int gsm48_decode_mobile_alloc(struct gsm48_sysinfo *s, uint8_t *ma, uint8_t len)
+{
+ int i, j = 0;
+ uint16_t f[len << 3];
- if (payload_len < 1 /* mobile allocation IE must be included */
- || *gh->data + 1 > payload_len) { /* short read of IE */
- DEBUGP(DRR, "Short read of immediate assignment message.\n");
- return -EINVAL;
- }
- if (*gh->data > 8) {
- DEBUGP(DRR, "moble allocation in immediate assignment too large.\n");
+ /* not more than 64 hopping indexes allowed in IE */
+ if (len > 8)
return -EINVAL;
+
+ /* tabula rasa */
+ s->hopp_len = 0;
+ for (i = 0; i < 1024; i++)
+ s->freq[i] &= ~FREQ_TYPE_HOPP;
+
+ /* generating list of all frequencies (1..1023,0) */
+ for (i = 1; i <= 1024; i++) {
+ if ((s->freq[i & 1023] & FREQ_TYPE_SERV)) {
+ f[j++] = i & 1023;
+ if (j == (len << 3))
+ break;
+ }
}
- /* request ref */
- if (gsm_match_ra(ms, ia->req_ref)) {
- /* channel description */
- 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 */
- memcpy(rr->mobile_alloc_lv, gh->data, *gh->data + 1);
- rr->wait_assing = 0;
- return gsm_rr_dl_est(ms);
+ /* 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)))) {
+ /* index higher than entries in list ? */
+ if (i >= j) {
+ DEBUGP(DRR, "Mobile Allocation hopping index "
+ "%d exceeds maximum number of cell "
+ "frequencies. (%d)\n", i + 1, j);
+ break;
+ }
+ hopping[s->hopp_len++] = f[i];
+ s->freq[f[i]] |= FREQ_TYPE_HOPP;
+ }
}
return 0;
}
-/* receive immediate assignment extended */
-static int gsm_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct gsm_msgb *msg)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm48_imm_ass_ext *ia = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*ia);
-
- /* 3.3.1.1.2: ignore assignment while idle */
- if (rr->state != GSM_RRSTATE_CONN_PEND || !rr->wait_assign)
- 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
+}
- if (payload_len < 1 /* mobile allocation IE must be included */
- || *gh->data + 1 > payload_len) { /* short read of IE */
- DEBUGP(DRR, "Short read of immediate assignment extended message.\n");
- return -EINVAL;
- }
- if (*gh->data > 4) {
- DEBUGP(DRR, "moble allocation in immediate assignment extended too large.\n");
- return -EINVAL;
- }
+/* 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;
- /* request ref 1 */
- if (gsm_match_ra(ms, ia->req_ref1)) {
- /* channel description */
- 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 */
- memcpy(rr->mobile_alloc_lv, gh->data, *gh->data + 1);
- rr->wait_assing = 0;
- return gsm_rr_dl_est(ms);
- }
- /* request ref 1 */
- if (gsm_match_ra(ms, ia->req_ref2)) {
- /* channel description */
- 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 */
- memcpy(rr->mobile_alloc_lv, gh->data, *gh->data + 1);
- rr->wait_assing = 0;
- return gsm_rr_dl_est(ms);
- }
+ 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;
}
-
-/* receive immediate assignment reject */
-static int gsm_rr_rx_imm_ass_rej(struct osmocom_ms *ms, struct gsm_msgb *msg)
+static int gsm48_decode_rach_ctl_neigh(struct gsm48_sysinfo *s, struct gsm48_rach_ctl *rc)
{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm48_imm_ass_rej *ia = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*ia);
int i;
- struct gsm48_req_ref *req_ref;
- uint8_t t3122_value;
- /* 3.3.1.1.2: ignore assignment while idle */
- if (rr->state != GSM_RRSTATE_CONN_PEND || !rr->wait_assign)
- return 0;
+ 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;
- if (payload_len < 0) {
- short:
- DEBUGP(DRR, "Short read of immediate assignment reject message.\n");
- return -EINVAL;
- }
+ return 0;
+}
- for (i = 0; i < 4; i++) {
- /* request reference */
- req_ref = (struct gsm48_req_ref *)(((uint8_t *)&ia->req_ref1) + i * 4);
- if (gsm_match_ra(ms, req_ref)) {
- /* wait indication */
- t3122_value = ((uint8_t *)&ia->wait_ind1) + i * 4;
- if (t3122_value)
- start_rr_t3122(rr, t3122_value, 0);
- /* start timer 3126 if not already */
- if (!timer_pending(rr->t3126))
- start_rr_t3126(rr, GSM_T3126_MS);
- /* stop assignmnet requests */
- rr->n_chan_req = 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)
+{
+}
- /* wait until timer 3126 expires, then release
- * or wait for channel assignment */
- 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)
+{
+}
- 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)
+{
}
-/* receive additional assignment */
-static int gsm_rr_rx_add_ass(struct osmocom_ms *ms, struct msgb *msg)
+/* 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)
{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_add_ass *aa = (struct gsm48_add_ass *)gh->data;
- int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*aa);
+}
+
+/* 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);
+ struct msgb *nmsg;
if (payload_len < 0) {
- DEBUGP(DRR, "Short read of ADDITIONAL ASSIGNMENT message.\n");
- return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 1 message.\n");
+ return -EINVAL;
}
- tlv_parse(&tp, &rsl_att_tlvdef, aa->data, payload_len, 0, 0);
+ /* Cell Channel Description */
+ gsm48_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(si->rest_octets, payload_len);
+
+ si->si1 = 1;
+
+ nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_sendmsg(ms, nmsg);
- return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
+ return 0;
}
-/*
- * measturement reports
- */
-
-static int gsm_rr_tx_meas_rep(struct osmocom_ms *ms)
+/* receive "SYSTEM INFORMATION 2" message (9.1.32) */
+static int gsm_rr_rx_sysinfo2(struct osmocom_ms *ms, struct msgb *msg)
{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm_rr_meas *meas = &rr->meas;
- struct msgb *msg = gsm48_rr_msgb_alloc();
- struct gsm48_hdr *gh;
- struct gsm48_meas_res *mr;
+ struct gsm48_system_information_type_2 *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+ struct msgb *nmsg;
- if (!msg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- mr = (struct gsm48_meas_res *) msgb_put(msg, sizeof(*mr));
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2 message.\n");
+ return -EINVAL;
+ }
+ /* Neighbor Cell Description */
+ gsm48_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 = si->ncc_permitted;
+ /* RACH Control Parameter */
+ gsm48_decode_rach_ctl_neigh(s, si->rach_control);
- gh->proto = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_MEAS_RES;
+ si->si2 = 1;
- /* measurement results */
- mr->rxlev_full = meas->rxlev_full;
- mr->rxlev_sub = meas->rxlev_sub;
- mr->rxqual_full = meas->rxqual_full;
- mr->rxqual_sub = meas->rxqual_sub;
- mr->dtx = meas->dtx;
- mr->ba = meas->ba;
- mr->meas_valid = meas->meas_valid;
- if (meas->ncell_na) {
- /* no results for serving cells */
- mr->no_n_hi = 1;
- mr->no_n_lo = 3;
- } else {
- mr->no_n_hi = meas->count >> 2;
- mr->no_n_lo = meas->count & 3;
- }
- rxlev_nc1 = meas->rxlev_nc[0];
- rxlev_nc2_hi = meas->rxlev_nc[1] >> 1;
- rxlev_nc2_lo = meas->rxlev_nc[1] & 1;
- rxlev_nc3_hi = meas->rxlev_nc[2] >> 2;
- rxlev_nc3_lo = meas->rxlev_nc[2] & 3;
- rxlev_nc4_hi = meas->rxlev_nc[3] >> 3;
- rxlev_nc4_lo = meas->rxlev_nc[3] & 7;
- rxlev_nc5_hi = meas->rxlev_nc[4] >> 4;
- rxlev_nc5_lo = meas->rxlev_nc[4] & 15;
- rxlev_nc6_hi = meas->rxlev_nc[5] >> 5;
- rxlev_nc6_lo = meas->rxlev_nc[5] & 31;
- bsic_nc1_hi = meas->bsic_nc[0] >> 3;
- bsic_nc1_lo = meas->bsic_nc[0] & 7;
- bsic_nc2_hi = meas->bsic_nc[1] >> 4;
- bsic_nc2_lo = meas->bsic_nc[1] & 15;
- bsic_nc3_hi = meas->bsic_nc[2] >> 5;
- bsic_nc3_lo = meas->bsic_nc[2] & 31;
- bsic_nc4 = meas->bsic_nc[3];
- bsic_nc5 = meas->bsic_nc[4];
- bsic_nc6 = meas->bsic_nc[5];
- bcch_f_nc1 = meas->bcch_f_nc[0];
- bcch_f_nc2 = meas->bcch_f_nc[1];
- bcch_f_nc3 = meas->bcch_f_nc[2];
- bcch_f_nc4 = meas->bcch_f_nc[3];
- bcch_f_nc5_hi = meas->bcch_f_nc[4] >> 1;
- bcch_f_nc5_lo = meas->bcch_f_nc[4] & 1;
- bcch_f_nc6_hi = meas->bcch_f_nc[5] >> 2;
- bcch_f_nc6_lo = meas->bcch_f_nc[5] & 3;
+ nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_sendmsg(ms, nmsg);
- //todo return rslms_data_req(ms, msg, 0);
+ return 0;
}
-/*
- * link establishment and release
- */
-
-/* activate link and send establish request */
-static int gsm_rr_dl_est(struct osmocom_ms *ms)
+/* receive "SYSTEM INFORMATION 2bis" message (9.1.33) */
+static int gsm_rr_rx_sysinfo2bis(struct osmocom_ms *ms, struct msgb *msg)
{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm_subscriber *subcr = ms->subscr;
- struct msgb *msg;
- struct gsm48_hdr *gh;
- struct gsm48_pag_rsp *pa;
+ struct gsm48_system_information_type_2bis *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+ struct msgb *nmsg;
- /* 3.3.1.1.3.1 */
- stop_rr_t3126(rr);
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2bis message.\n");
+ return -EINVAL;
+ }
+ /* Neighbor Cell Description */
+ s->nb_ext_ind = (si->bcch_frequency_list[0] >> 6) & 1;
+ s->nb_ba_ind = (si->bcch_frequency_list[0] >> 5) & 1;
+ gsm48_decode_freq_list(s->freq, si->ext_bcch_frequency_list,
+ sizeof(si->ext_bcch_frequency_list), 0x8e, FREQ_TYPE_NCELL_2bis);
+ /* RACH Control Parameter */
+ gsm48_decode_rach_ctl_neigh(s, si->rach_control);
- /* flush pending RACH requests */
- rr->n_chan_req = 0; // just to be safe
- msg = msgb_alloc_headroom(20, 16, "RAND_FLUSH");
- if (!msg)
+ si->si2bis = 1;
+
+ nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+ if (!nmsg)
return -ENOMEM;
- rslms_tx_rll_req_l3(ms, RSL_MT_RAND_ACC_FLSH, chan_nr, 0, msg);
+ gsm322_sendmsg(ms, nmsg);
- /* send DL_EST_REQ */
- if (rr->rr_est_msg) {
- /* use queued message */
- msg = rr->rr_est_msg;
- rr->rr_est_msg = 0;
- } else {
- uint8_t mi[11];
+ return 0;
+}
- /* create paging response */
- msg = gsm48_rr_msgb_alloc();
- if (!msg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- pr = (struct gsm48_pag_rsp *) msgb_put(msg, sizeof(*pr));
- /* key sequence */
- if (subscr->key_valid)
- pr->key_seq = subscr->key_seq;
- else
- pr->key_seq = 7;
- /* classmark 2 */
- cc->cm_len = sizeof(cm->cm2);
- gsm_rr_enc_cm2(ms, &cc->cm2)
- /* mobile identity */
- if (ms->subscr.tmsi_valid) {
- gsm48_generate_mid_from_tmsi(mi, subscr->tmsi);
- } else if (subscr->imsi[0])
- gsm48_generate_mid_from_imsi(mi, subscr->imsi);
- else {
- mi[1] = 1;
- mi[2] = 0xf0 | GSM_MI_TYPE_NONE;
- }
- msgb_put(msg, 1 + mi[1]);
- memcpy(cm->data, mi + 1, 1 + mi[1]);
+/* 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);
+ struct msgb *nmsg;
+
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2ter message.\n");
+ return -EINVAL;
}
+ /* Neighbor Cell Description 2 */
+ s->nb_multi_rep = (si->bcch_frequency_list[0] >> 6) & 3;
+ gsm48_decode_freq_list(s->freq, si->ext_bcch_frequency_list,
+ sizeof(si->ext_bcch_frequency_list), 0x8e, FREQ_TYPE_NCELL_2ter);
- /* activate channel */
- tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
+ si->si2ter = 1;
- /* start establishmnet */
- return rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_desc.chan_nr, 0, msg);
+ nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_sendmsg(ms, nmsg);
+
+ return 0;
}
-/* the link is established */
-static int gsm_rr_estab_cnf(struct osmocom_ms *ms, struct msgb *msg)
+/* receive "SYSTEM INFORMATION 3" message (9.1.35) */
+static int gsm_rr_rx_sysinfo3(struct osmocom_ms *ms, struct msgb *msg)
{
- struct msgb *newmsg;
- struct gsm_mm_hdr *newmmh;
+ struct gsm48_system_information_type_3 *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+ struct msgb *nmsg;
- /* if MM has releases before confirm, we start release */
- if (rr->state == GSM_RRSTATE_IDLE) {
- /* release message */
- newmsg = gsm48_rr_msgb_alloc();
- if (!newmsg)
- return -ENOMEM;
- /* start release */
- return rslms_tx_rll_req_l3(ms, RSL_MT_REL_REQ, 0, 0, newmsg);
+ 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_bcch(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 3 Rest Octets */
+ if (payload_len >= 4)
+ gsm48_decode_si3_rest(si->rest_octets, payload_len);
- /* 3.3.1.1.4 */
- new_rr_state(rr, GSM_RRSTATE_DEDICATED);
+ si->si3 = 1;
- /* send confirm to upper layer */
- newmsg = gsm48_mm_msgb_alloc();
- if (!newmsg)
+ nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+ if (!nmsg)
return -ENOMEM;
- newmmh = (struct gsm_mm_hdr *)newmsg->data;
- newmmh->msg_type = (rr->rr_est_req) ? RR_EST_CNF : RR_EST_IND;
- return rr_rcvmsg(ms, newmsg);
+ gsm322_sendmsg(ms, nmsg);
+
+ return 0;
}
-/* the link is released */
-static int gsm_rr_rel_cnf(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
+/* receive "SYSTEM INFORMATION 4" message (9.1.36) */
+static int gsm_rr_rx_sysinfo4(struct osmocom_ms *ms, struct msgb *msg)
{
- /* deactivate channel */
- tx_ph_dm_rel_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
+ struct gsm48_system_information_type_4 *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+ uint8_t *data = si->data;
+ struct msgb *nmsg;
+todo: si has different header in structures
- /* do nothing, because we aleady IDLE
- * or we received the rel cnf of the last connection
- * while already requesting a new one (CONN PEND)
- */
+ if (payload_len < 0) {
+ short_read:
+ 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 >= 1 && data[0] == GSM48_IE_CBCH_CHAN_DES) {
+ if (payload_len < 4)
+ goto short_read;
+ memcpy(&s->chan_desc, data + 1, sizeof(s->chan_desc));
+ payload_len -= 4;
+ data += 4;
+ }
+ /* CBCH Mobile Allocation */
+ if (payload_len >= 1 && data[0] == GSM48_IE_CBCH_MOB_ALLOC) {
+ if (payload_len < 1 || payload_len < 2 + data[1])
+ goto short_read;
+ gsm48_decode_mobile_alloc(&s, data + 2, si->data[1]);
+ payload_len -= 2 + data[1];
+ data += 2 + data[1];
+ }
+ /* SI 4 Rest Octets */
+ if (payload_len > 0)
+ gsm48_decode_si3_rest(data, payload_len);
+
+ si->si4 = 1;
+
+ nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_sendmsg(ms, nmsg);
return 0;
}
-/*
- * radio ressource requests
- */
-
-/* establish request for dedicated mode */
-static int gsm_rr_est_req(struct osmocom_ms *ms, struct msgb *msg)
+/* receive "SYSTEM INFORMATION 5" message (9.1.37) */
+static int gsm_rr_rx_sysinfo5(struct osmocom_ms *ms, struct msgb *msg)
{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm_mm_hdr *mmh = msgb->data;
- struct gsm48_hdr *gh = msgb_l3(msg);
-
- /* 3.3.1.1.3.2 */
- if (timer_pending(rr->t3122)) {
- if (rrmsg->cause != RR_EST_CAUSE_EMERGENCY) {
- struct msgb *newmsg;
- struct gsm_mm_hdr *newmmh;
+ struct gsm48_system_information_type_5 *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+ struct msgb *nmsg;
- newmsg = gsm48_mm_msgb_alloc();
- if (!newmsg)
- return -ENOMEM;
- newmmh = (struct gsm_mm_hdr *)newmsg->data;
- newmmh->msg_type RR_REL_IND;
- newmmh->cause = GSM_MM_CAUSE_T3122_PEND;
- return rr_rcvmsg(ms, newmsg);
- } else
- stop_rr_t3122(rr);
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 5 message.\n");
+ return -EINVAL;
}
+ /* Neighbor Cell Description */
+ gsm48_decode_freq_list(s->freq, si->bcch_frequency_list,
+ sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5);
- /* 3.3.1.1.1 */
- if (rrmsg->cause != RR_EST_CAUSE_EMERGENCY) {
- if (!(ms->access_class & ms->si.access_class)) {
- reject:
- if (!ms->opt.access_class_override) {
- struct msgb *newmsg;
- struct gsm_mm_hdr *newmmh;
+ si->si5 = 1;
- newmsg = gsm48_mm_msgb_alloc();
- if (!newmsg)
- return -ENOMEM;
- newmmh = (struct gsm_mm_hdr *)newmsg->data;
- newmmh->msg_type RR_REL_IND;
- newmmh->cause = GSM_MM_CAUSE_NOT_AUTHORIZED;
- return rr_rcvmsg(ms, newmsg);
- }
- }
- } else {
- if (!(ms->access_class & ms->si.access_class)
- && !ms->si.emergency)
- goto reject;
- }
+ nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_sendmsg(ms, nmsg);
- /* requested by RR */
- rr->rr_est_req = 1;
+ return 0;
+}
+
+/* receive "SYSTEM INFORMATION 5bis" message (9.1.38) */
+static int gsm_rr_rx_sysinfo5bis(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_system_information_type_5bis *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+ struct msgb *nmsg;
- /* clone and store REQUEST message */
- if (!gh) {
- printf("Error, missing l3 message\n");
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 5bis message.\n");
return -EINVAL;
}
- rr->rr_est_msg = msgb_alloc_headroom(256, 16, "EST_REQ");
- if (!rr->rr_est_msg)
+ /* Neighbor Cell Description */
+ gsm48_decode_freq_list(s->freq, si->bcch_frequency_list,
+ sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5bis);
+
+ si->si5bis = 1;
+
+ nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+ if (!nmsg)
return -ENOMEM;
- memcpy(msgb_put(rr_est_msg, msgb_l3len(msg)),
- msgb_l3(msg), msgb_l3len(msg));
+ gsm322_sendmsg(ms, nmsg);
- /* request channel */
- return gsm_rr_tx_chan_req(ms, mmh->cause);
+ return 0;
}
-/* send all queued messages down to layer 2 */
-static int gsm_rr_dequeue_down(struct osmocom_ms *ms)
+/* receive "SYSTEM INFORMATION 5ter" message (9.1.39) */
+static int gsm_rr_rx_sysinfo5ter(struct osmocom_ms *ms, struct msgb *msg)
{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct msgb *msg;
+ struct gsm48_system_information_type_5ter *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+ struct msgb *nmsg;
- while((msg = msgb_dequeue(&rr->downqueue))) {
- rslms_tx_rll_req_l3(ms, RSL_MT_DATA_REQ, chan_nr, 0, msg);
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 5ter message.\n");
+ return -EINVAL;
}
+ /* Neighbor Cell Description */
+ gsm48_decode_freq_list(s->freq, si->bcch_frequency_list,
+ sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5ter);
+
+ si->si5ter = 1;
+
+ nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_sendmsg(ms, nmsg);
return 0;
}
-/* 3.4.2 transfer data in dedicated mode */
-static int gsm_rr_data_req(struct osmocom_ms *ms, struct msgb *msg)
+/* receive "SYSTEM INFORMATION 6" message (9.1.39) */
+static int gsm_rr_rx_sysinfo6(struct osmocom_ms *ms, struct msgb *msg)
{
- struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm48_system_information_type_6 *si = msgb_l3(msg);
+ struct gsm48_sysinfo *s = ms->sysinfo;
+ int payload_len = msgb_l3len(msg) - sizeof(*si);
+ struct msgb *nmsg;
- if (rr->state != GSM_RRSTATE_DEDICATED) {
- msgb_free(msg)
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of SYSTEM INFORMATION 6 message.\n");
return -EINVAL;
}
-
- /* pull header */
- msgb_pull(msg, sizeof(struct gsm_mm_hdr));
+ /* Cell Identity */
+ s->cell_identity = ntohl(si->cell_identity);
+ /* LAI */
+ gsm48_decode_lai(si->lai, &s->mcc, &s->mnc, &s->lac);
+ /* Cell Options (SACCH) */
+ gsm48_decode_cellopt_sacch(s, si->control_channel_desc);
+ /* NCC Permitted */
+ s->nb_ncc_permitted = si->ncc_permitted;
+ /* SI 6 Rest Octets */
+ if (payload_len >= 4)
+ gsm48_decode_si6_rest(si->rest_octets, payload_len);
- /* queue message, during handover or assignment procedure */
- if (rr->hando_susp_state || rr->assign_susp_state) {
- msgb_enqueue(&rr->downqueue, msg);
- return 0;
- }
+ si->si6 = 1;
- /* forward message */
- return rslms_tx_rll_req_l3(ms, RSL_MT_DATA_REQ, chan_nr, 0, msg);
+ nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_sendmsg(ms, nmsg);
+
+ return 0;
}
/*
- * data indications from data link
+ * paging
*/
-/* 3.4.2 data from layer 2 to RR and upper layer*/
-static int gsm_rr_data_ind(struct osmocom_ms *ms, struct msbg *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t pdisc = gh->proto_discr & 0x0f;
-
- if (pdisc == GSM48_PDISC_RR) {
- int rc = -EINVAL;
+/* paging channel request */
+static int gsm_rr_chan2cause[4] = {
+ RR_EST_CAUSE_ANS_PAG_ANY,
+ RR_EST_CAUSE_ANS_PAG_SDCCH,
+ RR_EST_CAUSE_ANS_PAG_TCH_F,
+ RR_EST_CAUSE_ANS_PAG_TCH_ANY
+};
- switch(gh->msg_type) {
- case GSM48_MT_RR_ADD_ASS:
- rc = gsm_rr_rx_add_ass(ms, msg);
- break;
- case GSM48_MT_RR_ASS_CMD:
- rc = gsm_rr_rx_ass_cmd(ms, msg);
- break;
- case GSM48_MT_RR_CIP_MODE_CMD:
- rc = gsm_rr_rx_cip_mode_cmd(ms, msg);
- break;
- case GSM48_MT_RR_CLSM_ENQ:
- rc = gsm_rr_rx_cm_enq(ms, msg);
- break;
- case GSM48_MT_RR_HANDO_CMD:
- rc = gsm_rr_rx_hando_cmd(ms, msg);
- break;
- case GSM48_MT_RR_FREQ_REDEF:
- rc = gsm_rr_rx_freq_redef(ms, msg);
- break;
- default:
- DEBUGP(DRR, "Message type 0x%02x unknown.\n", gh->msg_type);
- }
+/* given LV of mobile identity is checked agains ms */
+static int gsm_match_mi(struct osmocom_ms *ms, u_int8_t mi)
+{
+ char imsi[16];
+ uint32_t tmsi;
- free_msgb(msg);
- return rc;
+ if (mi[0] < 1)
+ return 0;
+ mi_type = mi[1] & GSM_MI_TYPE_MASK;
+ switch (mi_type) {
+ case GSM_MI_TYPE_TMSI:
+ if (mi[0] < 5)
+ return;
+ memcpy(&tmsi, mi+2, 4);
+ if (ms->subscr.tmsi == ntohl(tmsi)
+ && ms->subscr.tmsi_valid)
+ return 1;
+ break;
+ case GSM_MI_TYPE_IMSI:
+ gsm48_mi_to_string(imsi, sizeof(imsi), mi + 1, mi[0]);
+ if (!strcmp(imsi, ms->subscr.imsi))
+ return 1;
+ break;
+ default:
+ DEBUGP(DRR, "paging with unsupported MI type %d.\n", mi_type);
}
- /* push header */
- msgb_push(msg, sizeof(struct gsm_mm_hdr));
- mmh = (struct gsm_mm_hdr *)msg->data;
- mmh->msg_type = RR_DATA_IND;
- /* forward message */
- return rr_rcvmsg(ms, msg);
+ return 0;
}
-/* unit data from layer 2 to RR layer */
-static int gsm_rr_unit_data_ind(struct osmocom_ms *ms, struct msgb *msg)
+/* paging request 1 message */
+static int gsm_rr_rx_pag_req_1(struct osmocom_ms *ms, struct msgb *msg)
{
- struct gsm48_hdr *gh = msgb_l3(msg);
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm48_rr_paging1 *pa = msgb_l3(msg);
+ int payload_len = msgb_l3len(msg) - sizeof(*pa);
+ int chan_first, chan_second;
+ uint8_t mi;
- switch (gh->msg_type) {
- case GSM48_MT_RR_PAG_REQ_1:
- return gsm_rr_rx_pag_req_1(ms, dlmsg->msg);
- case GSM48_MT_RR_PAG_REQ_2:
- return gsm_rr_rx_pag_req_2(ms, dlmsg->msg);
- case GSM48_MT_RR_PAG_REQ_3:
- return gsm_rr_rx_pag_req_3(ms, dlmsg->msg);
- case GSM48_MT_RR_IMM_ASS:
- return gsm_rr_rx_imm_ass(ms, dlmsg->msg);
- case GSM48_MT_RR_IMM_ASS_EXT:
- return gsm_rr_rx_imm_ass_ext(ms, dlmsg->msg);
- case GSM48_MT_RR_IMM_ASS_REJ:
- return gsm_rr_rx_imm_ass_rej(ms, dlmsg->msg);
- default:
- DEBUGP(DRR, "Message type 0x%02x unknown.\n", gh->msg_type);
+ /* 3.3.1.1.2: ignore paging while establishing */
+ if (rr->state != GSM_RRSTATE_IDLE)
+ return 0;
+
+ if (payload_len < 2) {
+ short:
+ DEBUGP(DRR, "Short read of paging request 1 message .\n");
return -EINVAL;
}
+
+ /* channel needed */
+ chan_first = pa->cneed1;
+ chan_second = pa->cneed2;
+ /* first MI */
+ mi = pa->data + 1;
+ if (payload_len < mi[0] + 1)
+ goto short;
+ if (gsm_match_mi(ms, mi) > 0)
+ return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_first]);
+ /* second MI */
+ payload_len -= mi[0] + 1;
+ mi = pa->data + mi[0] + 1;
+ if (payload_len < 2)
+ return 0;
+ if (mi[0] != GSM48_IE_MOBILE_ID)
+ return 0;
+ if (payload_len < mi[1] + 2)
+ goto short;
+ if (gsm_match_mi(ms, mi + 1) > 0)
+ return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_second]);
+
+ return 0;
}
+/* paging request 2 message */
+static int gsm_rr_rx_pag_req_2(struct osmocom_ms *ms, struct gsm_msgb *msg)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm48_rr_paging2 *pa = msgb_l3(msg);
+ int payload_len = msgb_l3len(msg) - sizeof(*pa);
+ uint32_t tmsi;
+ int chan_first, chan_second, chan_third;
+
+ /* 3.3.1.1.2: ignore paging while establishing */
+ if (rr->state != GSM_RRSTATE_IDLE)
+ return 0;
+ if (payload_len < 0) {
+ short:
+ DEBUGP(DRR, "Short read of paging request 2 message .\n");
+ return -EINVAL;
+ }
-complete
--------------------------------------------------------------------------------
-uncomplete
+ /* channel needed */
+ chan_first = pa->cneed1;
+ chan_second = pa->cneed2;
+ /* first MI */
+ if (ms->subscr.tmsi == ntohl(pa->tmsi1)
+ && ms->subscr.tmsi_valid)
+ return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_first]);
+ /* second MI */
+ if (ms->subscr.tmsi == ntohl(pa->tmsi2)
+ && ms->subscr.tmsi_valid)
+ return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_second]);
+ /* third MI */
+ mi = pa->data;
+ if (payload_len < 2)
+ return 0;
+ if (mi[0] != GSM48_IE_MOBILE_ID)
+ return 0;
+ if (payload_len < mi[1] + 2 + 1) /* must include "channel needed" */
+ goto short;
+ chan_third = mi[mi[1] + 2] & 0x03; /* channel needed */
+ if (gsm_match_mi(ms, mi + 1) > 0)
+ return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_third]);
+ return 0;
+}
+/* paging request 3 message */
+static int gsm_rr_rx_pag_req_3(struct osmocom_ms *ms, struct gsm_msgb *msg)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm48_rr_paging3 *pa = msgb_l3(msg);
+ int payload_len = msgb_l3len(msg) - sizeof(*pa);
+ uint32_t tmsi;
+ int chan_first, chan_second, chan_third, chan_fourth;
+ /* 3.3.1.1.2: ignore paging while establishing */
+ if (rr->state != GSM_RRSTATE_IDLE)
+ return 0;
+ if (payload_len < 0) { /* must include "channel needed", part of *pa */
+ short:
+ DEBUGP(DRR, "Short read of paging request 3 message .\n");
+ return -EINVAL;
+ }
+ /* channel needed */
+ chan_first = pa->cneed1;
+ chan_second = pa->cneed2;
+ chan_third = pa->cneed3;
+ chan_fourth = pa->cneed4;
+ /* first MI */
+ if (ms->subscr.tmsi == ntohl(pa->tmsi1)
+ && ms->subscr.tmsi_valid)
+ return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_first]);
+ /* second MI */
+ if (ms->subscr.tmsi == ntohl(pa->tmsi2)
+ && ms->subscr.tmsi_valid)
+ return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_second]);
+ /* thrid MI */
+ if (ms->subscr.tmsi == ntohl(pa->tmsi3)
+ && ms->subscr.tmsi_valid)
+ return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_third]);
+ /* fourth MI */
+ if (ms->subscr.tmsi == ntohl(pa->tmsi4)
+ && ms->subscr.tmsi_valid)
+ return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_fourth]);
+ return 0;
+}
+/*
+ * (immediate) assignment
+ */
+/* match request reference agains request history */
+static int gsm_match_ra(struct osmocom_ms *ms, struct gsm48_req_ref *req)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ int i;
+ for (i = 0; i < 3; i++) {
+ if (rr->cr_hist[i] >= 0
+ && ref->ra == rr->cr_hist[i]) {
+ // todo: match timeslot
+ return 1;
+ }
+ }
+ return 0;
+}
+/* transmit assignment complete after establishing link */
+static int gsm_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct msgb *msg;
+ struct gsm48_hdr *gh;
+ struct gsm48_ass_cpl *ac;
+ msg = gsm48_rr_msgb_alloc();
+ if (!msg)
+ return -ENOMEM;
+ gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+ ac = (struct gsm48_ass_cpl *) msgb_put(msg, sizeof(*ac));
+ gh->proto = GSM48_PDISC_RR;
+ gh->msg_type = GSM48_MT_RR_ASS_COMPL;
+ /* RR_CAUSE */
+ ac->rr_cause = cause;
+ return rslms_data_req(ms, msg, 0);
+}
+/* transmit failure to old link */
+static int gsm_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct msgb *msg;
+ struct gsm48_hdr *gh;
+ struct gsm48_ass_fail *ac;
-/*
- * system information
- */
+ msg = gsm48_rr_msgb_alloc();
+ if (!msg)
+ return -ENOMEM;
+ gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+ af = (struct gsm48_ass_fail *) msgb_put(msg, sizeof(*af));
-/* 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;
+ gh->proto = GSM48_PDISC_RR;
+ gh->msg_type = GSM48_MT_RR_ASS_COMPL;
- /* 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.
- */
+ /* RR_CAUSE */
+ af->rr_cause = cause;
- /* tabula rasa */
- for (i = 0; i < 1024; i++)
- f[i].used = 0;
+ return rslms_data_req(ms, msg, 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;
+/* receive immediate assignment */
+static int gsm_rr_rx_imm_ass(struct osmocom_ms *ms, struct gsm_msgb *msg)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm48_imm_ass *ia = msgb_l3(msg);
+ int payload_len = msgb_l3len(msg) - sizeof(*ia);
+ /* 3.3.1.1.2: ignore assignment while idle */
+ if (rr->state != GSM_RRSTATE_CONN_PEND || !rr->wait_assign)
return 0;
+
+ if (payload_len < 1 /* mobile allocation IE must be included */
+ || *gh->data + 1 > payload_len) { /* short read of IE */
+ DEBUGP(DRR, "Short read of immediate assignment message.\n");
+ return -EINVAL;
+ }
+ if (*gh->data > 8) {
+ DEBUGP(DRR, "moble allocation in immediate assignment too large.\n");
+ return -EINVAL;
}
- /* 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;
+ /* request ref */
+ if (gsm_match_ra(ms, ia->req_ref)) {
+ /* channel description */
+todo channel structure and right management of channel IEs
+ memset(&rr->chan_desc, 0, sizeof(cd));
+ /* timing advance */
+ rr->timing_advance = ia->timing_advance;
+ /* mobile allocation */
+ memcpy(rr->mobile_alloc_lv, gh->data, *gh->data + 1);
+ rr->wait_assing = 0;
+ return gsm_rr_dl_est(ms);
+ }
- /* 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;
+ return 0;
+}
- 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;
+/* receive immediate assignment extended */
+static int gsm_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct gsm_msgb *msg)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm48_imm_ass_ext *ia = msgb_l3(msg);
+ int payload_len = msgb_l3len(msg) - sizeof(*ia);
+ /* 3.3.1.1.2: ignore assignment while idle */
+ if (rr->state != GSM_RRSTATE_CONN_PEND || !rr->wait_assign)
return 0;
+
+ if (payload_len < 1 /* mobile allocation IE must be included */
+ || *gh->data + 1 > payload_len) { /* short read of IE */
+ DEBUGP(DRR, "Short read of immediate assignment extended message.\n");
+ return -EINVAL;
+ }
+ if (*gh->data > 4) {
+ DEBUGP(DRR, "moble allocation in immediate assignment extended too large.\n");
+ return -EINVAL;
}
- /* 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;
+ /* request ref 1 */
+ if (gsm_match_ra(ms, ia->req_ref1)) {
+ /* channel description */
+ 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 */
+ memcpy(rr->mobile_alloc_lv, gh->data, *gh->data + 1);
+ rr->wait_assing = 0;
+ return gsm_rr_dl_est(ms);
+ }
+ /* request ref 1 */
+ if (gsm_match_ra(ms, ia->req_ref2)) {
+ /* channel description */
+ 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 */
+ memcpy(rr->mobile_alloc_lv, gh->data, *gh->data + 1);
+ rr->wait_assing = 0;
+ return gsm_rr_dl_est(ms);
+ }
+
+ return 0;
+}
+
+/* receive immediate assignment reject */
+static int gsm_rr_rx_imm_ass_rej(struct osmocom_ms *ms, struct gsm_msgb *msg)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm48_imm_ass_rej *ia = msgb_l3(msg);
+ int payload_len = msgb_l3len(msg) - sizeof(*ia);
+ int i;
+ struct gsm48_req_ref *req_ref;
+ uint8_t t3122_value;
+ /* 3.3.1.1.2: ignore assignment while idle */
+ if (rr->state != GSM_RRSTATE_CONN_PEND || !rr->wait_assign)
return 0;
+
+ if (payload_len < 0) {
+ short:
+ DEBUGP(DRR, "Short read of immediate assignment reject message.\n");
+ return -EINVAL;
}
- /* 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;
+ for (i = 0; i < 4; i++) {
+ /* request reference */
+ req_ref = (struct gsm48_req_ref *)(((uint8_t *)&ia->req_ref1) + i * 4);
+ if (gsm_match_ra(ms, req_ref)) {
+ /* wait indication */
+ t3122_value = ((uint8_t *)&ia->wait_ind1) + i * 4;
+ if (t3122_value)
+ start_rr_t3122(rr, t3122_value, 0);
+ /* start timer 3126 if not already */
+ if (!timer_pending(rr->t3126))
+ start_rr_t3126(rr, GSM_T3126_MS);
+ /* stop assignmnet requests */
+ rr->n_chan_req = 0;
- return 0;
+ /* wait until timer 3126 expires, then release
+ * or wait for channel assignment */
+ 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;
+}
- return 0;
+/* receive additional assignment */
+static int gsm_rr_rx_add_ass(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ struct gsm48_add_ass *aa = (struct gsm48_add_ass *)gh->data;
+ int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*aa);
+
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of ADDITIONAL ASSIGNMENT message.\n");
+ return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
}
- /* 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;
+ tlv_parse(&tp, &rsl_att_tlvdef, aa->data, payload_len, 0, 0);
+
+ return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
+}
+
+/*
+ * measturement reports
+ */
+
+static int gsm_rr_tx_meas_rep(struct osmocom_ms *ms)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm_rr_meas *meas = &rr->meas;
+ struct msgb *msg;
+ struct gsm48_hdr *gh;
+ struct gsm48_meas_res *mr;
+
+ msg = gsm48_rr_msgb_alloc();
+ if (!msg)
+ return -ENOMEM;
+ gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+ mr = (struct gsm48_meas_res *) msgb_put(msg, sizeof(*mr));
- 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;
+ gh->proto = GSM48_PDISC_RR;
+ gh->msg_type = GSM48_MT_RR_MEAS_RES;
- return 0;
+ /* measurement results */
+ mr->rxlev_full = meas->rxlev_full;
+ mr->rxlev_sub = meas->rxlev_sub;
+ mr->rxqual_full = meas->rxqual_full;
+ mr->rxqual_sub = meas->rxqual_sub;
+ mr->dtx = meas->dtx;
+ mr->ba = meas->ba;
+ mr->meas_valid = meas->meas_valid;
+ if (meas->ncell_na) {
+ /* no results for serving cells */
+ mr->no_n_hi = 1;
+ mr->no_n_lo = 3;
+ } else {
+ mr->no_n_hi = meas->count >> 2;
+ mr->no_n_lo = meas->count & 3;
}
+ rxlev_nc1 = meas->rxlev_nc[0];
+ rxlev_nc2_hi = meas->rxlev_nc[1] >> 1;
+ rxlev_nc2_lo = meas->rxlev_nc[1] & 1;
+ rxlev_nc3_hi = meas->rxlev_nc[2] >> 2;
+ rxlev_nc3_lo = meas->rxlev_nc[2] & 3;
+ rxlev_nc4_hi = meas->rxlev_nc[3] >> 3;
+ rxlev_nc4_lo = meas->rxlev_nc[3] & 7;
+ rxlev_nc5_hi = meas->rxlev_nc[4] >> 4;
+ rxlev_nc5_lo = meas->rxlev_nc[4] & 15;
+ rxlev_nc6_hi = meas->rxlev_nc[5] >> 5;
+ rxlev_nc6_lo = meas->rxlev_nc[5] & 31;
+ bsic_nc1_hi = meas->bsic_nc[0] >> 3;
+ bsic_nc1_lo = meas->bsic_nc[0] & 7;
+ bsic_nc2_hi = meas->bsic_nc[1] >> 4;
+ bsic_nc2_lo = meas->bsic_nc[1] & 15;
+ bsic_nc3_hi = meas->bsic_nc[2] >> 5;
+ bsic_nc3_lo = meas->bsic_nc[2] & 31;
+ bsic_nc4 = meas->bsic_nc[3];
+ bsic_nc5 = meas->bsic_nc[4];
+ bsic_nc6 = meas->bsic_nc[5];
+ bcch_f_nc1 = meas->bcch_f_nc[0];
+ bcch_f_nc2 = meas->bcch_f_nc[1];
+ bcch_f_nc3 = meas->bcch_f_nc[2];
+ bcch_f_nc4 = meas->bcch_f_nc[3];
+ bcch_f_nc5_hi = meas->bcch_f_nc[4] >> 1;
+ bcch_f_nc5_lo = meas->bcch_f_nc[4] & 1;
+ bcch_f_nc6_hi = meas->bcch_f_nc[5] >> 2;
+ bcch_f_nc6_lo = meas->bcch_f_nc[5] & 3;
+ //todo return rslms_data_req(ms, msg, 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;
-}
+/*
+ * link establishment and release
+ */
-/* decode "Cell Options (BCCH)" (10.5.2.3) */
-static int gsm48_decode_cellopt(struct gsm48_sysinfo *s, struct gsm48_cell_options *co)
+/* activate link and send establish request */
+static int gsm_rr_dl_est(struct osmocom_ms *ms)
{
- 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;
-}
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm_subscriber *subcr = ms->subscr;
+ struct msgb *msg;
+ struct gsm48_hdr *gh;
+ struct gsm48_pag_rsp *pa;
-/* 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 */
-}
+ /* 3.3.1.1.3.1 */
+ stop_rr_t3126(rr);
-/* 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
-}
+ /* flush pending RACH requests */
+ rr->n_chan_req = 0; // just to be safe
+ msg = msgb_alloc_headroom(20, 16, "RAND_FLUSH");
+ if (!msg)
+ return -ENOMEM;
+ rslms_tx_rll_req_l3(ms, RSL_MT_RAND_ACC_FLSH, chan_nr, 0, msg);
-/* 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;
+ /* send DL_EST_REQ */
+ if (rr->rr_est_msg) {
+ /* use queued message */
+ msg = rr->rr_est_msg;
+ rr->rr_est_msg = 0;
+ } else {
+ uint8_t mi[11];
- 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;
+ /* create paging response */
+ msg = gsm48_rr_msgb_alloc();
+ if (!msg)
+ return -ENOMEM;
+ gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+ pr = (struct gsm48_pag_rsp *) msgb_put(msg, sizeof(*pr));
+ /* key sequence */
+ if (subscr->key_valid)
+ pr->key_seq = subscr->key_seq;
else
- s->class_barr[i] = 0;
+ pr->key_seq = 7;
+ /* classmark 2 */
+ cc->cm_len = sizeof(cm->cm2);
+ gsm_rr_enc_cm2(ms, &cc->cm2)
+ /* mobile identity */
+ if (ms->subscr.tmsi_valid) {
+ gsm48_generate_mid_from_tmsi(mi, subscr->tmsi);
+ } else if (subscr->imsi[0])
+ gsm48_generate_mid_from_imsi(mi, subscr->imsi);
+ else {
+ mi[1] = 1;
+ mi[2] = 0xf0 | GSM_MI_TYPE_NONE;
+ }
+ msgb_put(msg, 1 + mi[1]);
+ memcpy(cm->data, mi + 1, 1 + mi[1]);
+ }
- return 0;
+ /* activate channel */
+ 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_desc.chan_nr, 0, msg);
}
-static int gsm48_decode_rach_ctl_neigh(struct gsm48_sysinfo *s, struct gsm48_rach_ctl *rc)
+
+/* the link is established */
+static int gsm_rr_estab_cnf(struct osmocom_ms *ms, struct msgb *msg)
{
- int i;
+ struct msgb *nmsg;
+ struct gsm_mm_hdr *nmmh;
- 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;
+ /* if MM has releases before confirm, we start release */
+ if (rr->state == GSM_RRSTATE_IDLE) {
+ /* release message */
+ nmsg = gsm48_rr_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ /* start release */
+ return rslms_tx_rll_req_l3(ms, RSL_MT_REL_REQ, 0, 0, nmsg);
+ }
- return 0;
-}
+ /* 3.3.1.1.4 */
+ new_rr_state(rr, GSM_RRSTATE_DEDICATED);
-/* 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)
-{
+ /* send confirm to upper layer */
+ nmsg = gsm48_mm_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ nmmh = (struct gsm_mm_hdr *)nmsg->data;
+ nmmh->msg_type = (rr->rr_est_req) ? RR_EST_CNF : RR_EST_IND;
+ return gsm48_mm_upmsg(ms, nmsg);
}
-/* 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)
+/* the link is released */
+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_desc.chan_nr);
+
+ /* do nothing, because we aleady IDLE
+ * or we received the rel cnf of the last connection
+ * while already requesting a new one (CONN PEND)
+ */
+
+ return 0;
}
+/*
+ * radio ressource requests
+ */
-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)
+/* establish request for dedicated mode */
+static int gsm_rr_est_req(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);
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct gsm_mm_hdr *mmh = msgb->data;
+ struct gsm48_hdr *gh = msgb_l3(msg);
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 1 message.\n");
+ /* 3.3.1.1.3.2 */
+ if (timer_pending(rr->t3122)) {
+ if (rrmsg->cause != RR_EST_CAUSE_EMERGENCY) {
+ struct msgb *nmsg;
+ struct gsm_mm_hdr *nmmh;
+
+ nmsg = gsm48_mm_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ nmmh = (struct gsm_mm_hdr *)nmsg->data;
+ nmmh->msg_type RR_REL_IND;
+ nmmh->cause = GSM_MM_CAUSE_T3122_PEND;
+ return gsm48_mm_upmsg(ms, nmsg);
+ } else
+ stop_rr_t3122(rr);
+ }
+
+ /* 3.3.1.1.1 */
+ if (rrmsg->cause != RR_EST_CAUSE_EMERGENCY) {
+ if (!(ms->access_class & ms->si.access_class)) {
+ reject:
+ if (!ms->opt.access_class_override) {
+ struct msgb *nmsg;
+ struct gsm_mm_hdr *nmmh;
+
+ nmsg = gsm48_mm_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ nmmh = (struct gsm_mm_hdr *)nmsg->data;
+ nmmh->msg_type RR_REL_IND;
+ nmmh->cause = GSM_MM_CAUSE_NOT_AUTHORIZED;
+ return gsm48_mm_upmsg(ms, nmsg);
+ }
+ }
+ } else {
+ if (!(ms->access_class & ms->si.access_class)
+ && !ms->si.emergency)
+ goto reject;
+ }
+
+ /* requested by RR */
+ rr->rr_est_req = 1;
+
+ /* clone and store REQUEST message */
+ if (!gh) {
+ printf("Error, missing l3 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);
+ rr->rr_est_msg = msgb_alloc_headroom(256, 16, "EST_REQ");
+ if (!rr->rr_est_msg)
+ return -ENOMEM;
+ memcpy(msgb_put(rr_est_msg, msgb_l3len(msg)),
+ msgb_l3(msg), msgb_l3len(msg));
- return 0;
+ /* request channel */
+ return gsm_rr_tx_chan_req(ms, mmh->cause);
}
-
-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)
+/* send all queued messages down to layer 2 */
+static int gsm_rr_dequeue_down(struct osmocom_ms *ms)
{
- struct gsm48_system_information_type_2 *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct msgb *msg;
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2 message.\n");
- return -EINVAL;
+ while((msg = msgb_dequeue(&rr->downqueue))) {
+ rslms_tx_rll_req_l3(ms, RSL_MT_DATA_REQ, chan_nr, 0, msg);
}
- /* 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)
+/* 3.4.2 transfer data in dedicated mode */
+static int gsm_rr_data_req(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);
+ struct gsm_rrlayer *rr = ms->rrlayer;
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2bis message.\n");
+ if (rr->state != GSM_RRSTATE_DEDICATED) {
+ msgb_free(msg)
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);
+
+ /* pull header */
+ msgb_pull(msg, sizeof(struct gsm_mm_hdr));
- return 0;
+ /* 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);
}
+/*
+ * data indications from data link
+ */
-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)
+/* 3.4.2 data from layer 2 to RR and upper layer*/
+static int gsm_rr_data_ind(struct osmocom_ms *ms, struct msbg *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);
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ u_int8_t pdisc = gh->proto_discr & 0x0f;
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2ter message.\n");
- return -EINVAL;
+ if (pdisc == GSM48_PDISC_RR) {
+ int rc = -EINVAL;
+
+ switch(gh->msg_type) {
+ case GSM48_MT_RR_ADD_ASS:
+ rc = gsm_rr_rx_add_ass(ms, msg);
+ break;
+ case GSM48_MT_RR_ASS_CMD:
+ rc = gsm_rr_rx_ass_cmd(ms, msg);
+ break;
+ case GSM48_MT_RR_CIP_MODE_CMD:
+ rc = gsm_rr_rx_cip_mode_cmd(ms, msg);
+ break;
+ case GSM48_MT_RR_CLSM_ENQ:
+ rc = gsm_rr_rx_cm_enq(ms, msg);
+ break;
+ case GSM48_MT_RR_HANDO_CMD:
+ rc = gsm_rr_rx_hando_cmd(ms, msg);
+ break;
+ case GSM48_MT_RR_FREQ_REDEF:
+ rc = gsm_rr_rx_freq_redef(ms, msg);
+ break;
+ default:
+ DEBUGP(DRR, "Message type 0x%02x unknown.\n", gh->msg_type);
+ }
+
+ free_msgb(msg);
+ return rc;
}
- /* 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;
+ /* push header */
+ msgb_push(msg, sizeof(struct gsm48_mm_hdr));
+ mmh = (struct gsm48_mm_hdr *)msg->data;
+ mmh->msg_type = RR_DATA_IND;
+
+ return gsm48_mm_upmsg(ms, msg);
}
-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)
+/* unit data from layer 2 to RR layer */
+static int gsm_rr_unit_data_ind(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);
+ struct gsm48_hdr *gh = msgb_l3(msg);
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 3 message.\n");
+ switch (gh->msg_type) {
+ case GSM48_MT_RR_SYSINFO_1:
+ return gsm_rr_rx_sysinfo1(ms, dlmsg->msg);
+ case GSM48_MT_RR_SYSINFO_2:
+ return gsm_rr_rx_sysinfo2(ms, dlmsg->msg);
+ case GSM48_MT_RR_SYSINFO_2bis:
+ return gsm_rr_rx_sysinfo2bis(ms, dlmsg->msg);
+ case GSM48_MT_RR_SYSINFO_2ter:
+ return gsm_rr_rx_sysinfo2ter(ms, dlmsg->msg);
+ case GSM48_MT_RR_SYSINFO_3:
+ return gsm_rr_rx_sysinfo3(ms, dlmsg->msg);
+ case GSM48_MT_RR_SYSINFO_4:
+ return gsm_rr_rx_sysinfo4(ms, dlmsg->msg);
+ case GSM48_MT_RR_SYSINFO_5:
+ return gsm_rr_rx_sysinfo5(ms, dlmsg->msg);
+ case GSM48_MT_RR_SYSINFO_5bis:
+ return gsm_rr_rx_sysinfo5bis(ms, dlmsg->msg);
+ case GSM48_MT_RR_SYSINFO_5ter:
+ return gsm_rr_rx_sysinfo5ter(ms, dlmsg->msg);
+ case GSM48_MT_RR_SYSINFO_6:
+ return gsm_rr_rx_sysinfo6(ms, dlmsg->msg);
+ case GSM48_MT_RR_PAG_REQ_1:
+ return gsm_rr_rx_pag_req_1(ms, dlmsg->msg);
+ case GSM48_MT_RR_PAG_REQ_2:
+ return gsm_rr_rx_pag_req_2(ms, dlmsg->msg);
+ case GSM48_MT_RR_PAG_REQ_3:
+ return gsm_rr_rx_pag_req_3(ms, dlmsg->msg);
+ case GSM48_MT_RR_IMM_ASS:
+ return gsm_rr_rx_imm_ass(ms, dlmsg->msg);
+ case GSM48_MT_RR_IMM_ASS_EXT:
+ return gsm_rr_rx_imm_ass_ext(ms, dlmsg->msg);
+ case GSM48_MT_RR_IMM_ASS_REJ:
+ return gsm_rr_rx_imm_ass_rej(ms, dlmsg->msg);
+ default:
+ DEBUGP(DRR, "Message type 0x%02x unknown.\n", gh->msg_type);
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;
-}
+the process above is complete
+------------------------------------------------------------------------------
+incomplete
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-today: decode mobile alloc 1-8 binary masks
#include <osmocore/protocol/gsm_04_08.h>
#include <osmocore/msgb.h>
+#include <osmocore/utils.h>
#include <osmocore/gsm48.h>
-static struct rr_names {
- char *name;
- int value;
-} rr_names[] = {
- { "RR_EST_REQ", RR_EST_REQ },
- { "RR_EST_IND", RR_EST_IND },
- { "RR_EST_CNF", RR_EST_CNF },
- { "RR_REL_IND", RR_REL_IND },
- { "RR_SYNC_IND", RR_SYNC_IND },
- { "RR_DATA_REQ", RR_DATA_REQ },
- { "RR_DATA_IND", RR_DATA_IND },
- { "RR_UNIT_DATA_IND", RR_UNIT_DATA_IND },
- { "RR_ABORT_REQ", RR_ABORT_REQ },
- { "RR_ABORT_IND", RR_ABORT_IND },
- { "RR_ACT_REQ", RR_ACT_REQ },
-
- {NULL, 0}
+static const struct value_string rr_names[] = {
+ { RR_EST_REQ, "RR_EST_REQ" },
+ { RR_EST_IND, "RR_EST_IND" },
+ { RR_EST_CNF, "RR_EST_CNF" },
+ { RR_REL_IND, "RR_REL_IND" },
+ { RR_SYNC_IND, "RR_SYNC_IND" },
+ { RR_DATA_REQ, "RR_DATA_REQ" },
+ { RR_DATA_IND, "RR_DATA_IND" },
+ { RR_UNIT_DATA_IND, "RR_UNIT_DATA_IND" },
+ { RR_ABORT_REQ, "RR_ABORT_REQ" },
+ { RR_ABORT_IND, "RR_ABORT_IND" },
+ { RR_ACT_REQ, "RR_ACT_REQ" },
+ { 0, NULL }
};
-char *get_rr_name(int value)
+const char *get_rr_name(int value)
{
- int i;
-
- for (i = 0; rr_names[i].name; i++) {
- if (rr_names[i].value == value)
- return rr_names[i].name;
- }
-
- return "RR_Unknown";
+ return get_value_string(rr_names, value);
}
-static int rr_rcvmsg(struct osmocom_ms *ms,
+move to mm
+static int gsm48_mm_upmsg(struct osmocom_ms *ms,
int msg_type, struct gsm_mncc *rrmsg)
{
struct msgb *msg;
+#if 0
DEBUGP(DRR, "(MS %s) Sending '%s' to MM.\n", ms->name,
get_rr_name(msg_type));
+#endif
rrmsg->msg_type = msg_type;
/* state trasitions for radio ressource messages (upper layer) */
static struct rrdownstate {
- u_int32_t states;
+ uint32_t states;
int type;
int (*rout) (struct osmocom_ms *ms, struct gsm_dl *rrmsg);
} rrdownstatelist[] = {
#define RRDOWNSLLEN \
(sizeof(rrdownstatelist) / sizeof(struct rrdownstate))
-static int gsm_send_rr(struct osmocom_ms *ms, struct gsm_rr *msg)
+static int gsm48_rr_sendmsg(struct osmocom_ms *ms, struct gsm_rr *msg)
{
struct gsm_mm_hdr *mmh = msgb->data;
int msg_type = mmh->msg_type;
DEBUGP(DRR, "(ms %s) Sending '%s' to DL in state %s\n", ms->name,
- gsm0408_rr_msg_names[msg_type], mm_state_names[mm->state]);
+ gsm48_rr_msg_name(msg_type), mm_state_names[mm->state]);
/* find function for current state and message */
for (i = 0; i < RRDOWNSLLEN; i++)
break;
if (i == RRDOWNSLLEN) {
DEBUGP(DRR, "Message unhandled at this state.\n");
+ free_msgb(msg);
+todo: in all functions of this type: free_msgb must be called if unhandled.
return 0;
}
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;
memcpy(&rr->chan_desc, cd, sizeof(cd));
/* start suspension of current link */
- newmsg = gsm48_rr_msgb_alloc();
- if (!newmsg)
+ nmsg = gsm48_rr_msgb_alloc();
+ if (!nmsg)
return -ENOMEM;
rslms_tx_rll_req_l3(ms, RSL_MT_SUSP_REQ, rr->chan_desc.chan_nr, 0, msg);
return 0;
}
- - queue messages during this state
- - flush/send when leaving this state
+/* decode "Cell Description" (10.5.2.2) */
+static int gsm48_decode_cell_desc(struct gsm48_cell_desc *cd, uint16_t *arfcn, uint8_t *ncc uint8_t *bcc)
+{
+ *arfcn = (cd->bcch_hi << 8) + cd->bcch_lo;
+ *ncc = cd->ncc;
+ *bcc = cd->bcc;
+}
+
+/* decode "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 gsm_rrlayer *rr, struct gsm_rr_sync_ind *si)
+{
+ rr->ho_sync_ind = si->si;
+ rr->ho_rot = si->rot;
+ rr->ho_nci = si->nci;
+}
+
+/* receiving HANDOVER COMMAND message (9.1.15) */
static int gsm_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm_rrlayer *rr = ms->rrlayer;
struct gsm48_hdr *gh = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*gh);
+ struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *)gh->data;
+ int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*ho);
+ struct tlv_parsed tp;
+ struct gsm_rr_chan_desc cd;
+
+ memset(&cd, 0, sizeof(cd));
+
+ if (payload_len < 0) {
+ DEBUGP(DRR, "Short read of HANDOVER COMMAND message.\n");
+ return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
+ }
+ tlv_parse(&tp, &rsl_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_MOBILE_ALLOC)-1, &cd);
+ /* Frequency Sort List */
+ if (TLVP_PRESENT(&tp, GSM48_IE_FREQ_SHORT_LIST))
+ gsm48_decode_freq_list(s->freq,
+ TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC),
+ *(TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC)-1),
+ 0xce, FREQ_TYPE_SERV);
+
+
+today: more IE parsing
- 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));
- send dl suspend req
+ /* start suspension of current link */
+ nmsg = gsm48_rr_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ rslms_tx_rll_req_l3(ms, RSL_MT_SUSP_REQ, rr->chan_desc.chan_nr, 0, msg);
/* change into special handover suspension state */
rr->hando_susp_state = 1;
rr->resume_last_state = 0;
+
+ return 0;
}
static int gsm_rr_rx_hando_cmd(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;
- gsm_rr_tx_ass_cpl(ms, cause);
- flush queued radio ressource messages
-
- return 0;
+ gsm_rr_tx_ass_cpl(ms, GSM48_RR_CAUSE_NORMAL);
} else {
gsm_rr_tx_ass_fail(ms, RR_CAUSE_PROTO_ERR_UNSPEC);
- return 0;
}
+ /* transmit queued frames during ho / ass transition */
+ gsm_rr_dequeue_down(ms);
}
+
+ return 0;
}
static int gsm_rr_connect_cnf(struct osmocom_ms *ms, struct msgbl *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)
+ nmsg = gsm48_rr_msgb_alloc();
+ if (!nmsg)
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);
+ rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_desc.chan_nr, 0, nmsg);
}
if (rr->hando_susp_state) {
- send HANDOVER ACCESS via DL_RANDOM_ACCESS_REQ
+ gsm_rr_tx_hando_access(ms);
rr->hando_acc_left = 3;
}
return 0;
static int gsm_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm_rrlayer *rr = ms->rrlayer;
- struct msgb *newmsg;
- struct gsm_mm_hdr *newmmh;
+ struct msgb *nmsg;
+ struct gsm_mm_hdr *nmmh;
if (rr->hando_susp_state || rr->assign_susp_state) {
if (!rr->resume_last_state) {
/* change radio to old channel */
tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
- return 0;
+ /* re-establish old link */
+ nmsg = gsm48_rr_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ return rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_desc.chan_nr, 0, nmsg);
}
rr->resume_last_state = 0;
}
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();
+ nmsg = 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);
+ nmmh = (struct gsm_mm_hdr *)nmsg->data;
+ nmmh->msg_type = RR_ABORT_IND;
+ nmmh->cause = GSM_MM_CAUSE_LINK_FAILURE;
+ return gsm48_mm_upmsg(ms, msg);
}
/* state trasitions for link layer messages (lower layer) */
static struct dldatastate {
- u_int32_t states;
+ uint32_t states;
int type;
int (*rout) (struct osmocom_ms *ms, struct gsm_dl *dlmsg);
} dldatastatelist[] = {
#define DLDATASLLEN \
(sizeof(dldatastatelist) / sizeof(struct dldatastate))
-static int gsm_rcv_dl(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
+static int gsm48_rcv_dl(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
{
int msg_type = dlmsg->msg_type;
DEBUGP(DRR, "(ms %s) Received '%s' from DL in state %s\n", ms->name,
- gsm0408_dl_msg_names[msg_type], mm_state_names[mm->state]);
+ gsm48_dl_msg_name(msg_type), mm_state_names[mm->state]);
/* find function for current state and message */
for (i = 0; i < DLDATASLLEN; i++)
break;
if (i == DLDATASLLEN) {
DEBUGP(DRR, "Message unhandled at this state.\n");
+ free_msgb(msg);
return 0;
}
return rc;
}
+/* dequeue messages from dl */
+int gsm48_rr_queue(struct osmocom_ms *ms)
+{
+ struct gsm_rrlayer *rr = ms->rrlayer;
+ struct msgb *msg;
+ int work = 0;
+
+ while ((msg = msgb_dequeue(&rr->up_queue))) {
+ /* msg is freed there */
+ gsm48_rcv_dl(ms, msg);
+ work = 1; /* work done */
+ }
+
+ return work;
+}
+
static void timeout_rr_t3124(void *arg)
{
struct gsm_rrlayer *rr = arg;
+ /* stop sending more access bursts when timer expired */
+ hando_acc_left = 0;
+
+ /* 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);
+
+ /* re-establish old link */
+ msg = gsm48_rr_msgb_alloc();
+ if (!msg)
+ return -ENOMEM;
+ return rslms_tx_rll_req_l3(ms, RSL_MT_EST_REQ, rr->chan_desc.chan_desc.chan_nr, 0, msg);
+
todo
}
return NULL;
rr->ms = ms;
- init queues
-
- init timers
+ INIT_LLIST_HEAD(&rr->up_queue);
return;
}
return;
}
+/* send HANDOVER ACCESS burst (9.1.14) */
+static int gsm_rr_tx_hando_access(struct osmocom_ms *ms)
+{
+ nmsg = msgb_alloc_headroom(20, 16, "HAND_ACCESS");
+ if (!nmsg)
+ return -ENOMEM;
+ *msgb_put(nmsg, 1) = rr->hando_ref;
+ return rslms_tx_rll_req_l3(ms, RSL_MT_RAND_ACC_REQ, chan_nr, 0, nmsg);
+}
+
/* send next channel request in dedicated state */
static int gsm_rr_rand_acc_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm_rrlayer *rr = ms->rrlayer;
- struct msgb *newmsg;
+ struct msgb *nmsg;
int s;
if (!rr->hando_susp_state) {
/* send up to four handover access bursts */
if (rr->hando_acc_left) {
rr->hando_acc_left--;
- send HANDOVER ACCESS via DL_RANDOM_ACCESS_REQ;
+ gsm_rr_tx_hando_access(ms);
return;
}
- if (!timer 3124 running) {
+ /* start timer for sending next HANDOVER ACCESS bursts afterwards */
+ if (!timer_pending(&rr->t3124)) {
if (allocated channel is SDCCH)
start_rr_t3124(rr, GSM_T3124_675);
else
}
rr->n_chan_req--;
- /* table 3.1 */
- switch(ms->si.tx_integer) {
- case 3: case 8: case 14: case 50:
- if (ms->si.bcch_type == GSM_NON_COMBINED_CCCH)
- s = 55;
- else
- s = 41;
- case 4: case 9: case 16:
- if (ms->si.bcch_type == GSM_NON_COMBINED_CCCH)
- s = 76;
- else
- s = 52;
- case 5: case 10: case 20:
- if (ms->si.bcch_type == GSM_NON_COMBINED_CCCH)
- s = 109;
- else
- s = 58;
- case 6: case 11: case 25:
- if (ms->si.bcch_type == GSM_NON_COMBINED_CCCH)
- s = 163;
- else
- s = 86;
- default:
- if (ms->si.bcch_type == GSM_NON_COMBINED_CCCH)
- s = 217;
- else
- s = 115;
+ /* wait for PHYSICAL INFORMATION message or T3124 timeout */
+ return 0;
- /* resend chan_req */
- newmsg = msgb_alloc_headroom(20, 16, "CHAN_REQ");
- if (!newmsg)
- return -ENOMEM;
- *msgb_put(newmsg, 1) = rr->chan_req;
- *msgb_put(newmsg, 1) = (random() % ms->si.tx_integer) + s; /* delay */
- rr->cr_hist[3] = rr->cr_hist[2];
- rr->cr_hist[2] = rr->cr_hist[1];
- rr->cr_hist[1] = chan_req;
- return rslms_tx_rll_req_l3(ms, RSL_MT_RAND_ACC_REQ, chan_nr, 0, newmsg);
}