+#warning rr on MDL error handling (as specified in 04.08 / 04.06)
/*
* (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
*
#include <osmocore/gsm48.h>
#include <osmocore/bitvec.h>
-#include <osmocom/logging.h>
#include <osmocom/osmocom_data.h>
+#include <osmocom/l1l2_interface.h>
+#include <osmocom/logging.h>
+#include <osmocom/networks.h>
+#include <osmocom/l1ctl.h>
static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg);
static int gsm48_rr_dl_est(struct osmocom_ms *ms);
int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc,
uint16_t *mnc, uint16_t *lac)
{
- *mcc = (lai->digits[0] & 0x0f) * 100
- + (lai->digits[0] >> 4) * 10
- + (lai->digits[1] & 0x0f);
- *mnc = (lai->digits[2] & 0x0f) * 10
- + (lai->digits[2] >> 4);
- if ((lai->digits[1] >> 4) != 0xf) /* 3 digits MNC */
- *mnc += (lai->digits[1] >> 4) * 100;
+ *mcc = ((lai->digits[0] & 0x0f) << 8)
+ | (lai->digits[0] & 0xf0)
+ | (lai->digits[1] & 0x0f);
+ *mnc = ((lai->digits[2] & 0x0f) << 8)
+ | (lai->digits[2] & 0xf0)
+ | ((lai->digits[1] & 0xf0) >> 4);
*lac = ntohs(lai->lac);
return 0;
return 0;
}
+/* decode "BA Range" (10.5.2.1a) */
+static int gsm48_decode_ba_range(const uint8_t *ba, uint8_t ba_len,
+ uint32_t *range, uint8_t *ranges, int max_ranges)
+{
+ /* ba = pointer to IE without IE type and length octets
+ * ba_len = number of octets
+ * range = pointer to store decoded range
+ * ranges = number of ranges decoded
+ * max_ranges = maximum number of decoded ranges that can be stored
+ */
+ uint16_t lower, higher;
+ int i, n, required_octets;
+
+ /* find out how much ba ranges will be decoded */
+ n = *ba++;
+ ba_len --;
+ required_octets = 5 * (n >> 1) + 3 * (n & 1);
+ if (required_octets > ba_len) {
+ LOGP(DRR, LOGL_NOTICE, "BA range IE too short: %d ranges "
+ "require %d octets, but only %d octets remain.\n",
+ n, required_octets, ba_len);
+ *ranges = 0;
+ return -EINVAL;
+ }
+ if (max_ranges > n)
+ LOGP(DRR, LOGL_NOTICE, "BA range %d exceed the maximum number "
+ "of ranges supported by this mobile (%d).\n",
+ n, max_ranges);
+ n = max_ranges;
+
+ /* decode ranges */
+ for (i = 0; i < n; i++) {
+ if (!(i & 1)) {
+ /* decode even range number */
+ lower = *ba++ << 2;
+ lower |= (*ba >> 6);
+ higher = (*ba++ & 0x3f) << 4;
+ higher |= *ba >> 4;
+ } else {
+ lower = (*ba++ & 0x0f) << 6;
+ lower |= *ba >> 2;
+ higher = (*ba++ & 0x03) << 8;
+ higher |= *ba++;
+ /* decode odd range number */
+ }
+ *range++ = (higher << 16) | lower;
+ }
+ *ranges = n;
+
+ return 0;
+}
+
/*
* state transition
*/
-static const char *gsm48_rr_state_names[] = {
- "IDLE",
- "CONN PEND",
- "DEDICATED",
+const char *gsm48_rr_state_names[] = {
+ "idle",
+ "connection pending",
+ "dedicated",
+ "release pending",
};
static void new_rr_state(struct gsm48_rrlayer *rr, int state)
(sizeof(gsm48_rr_state_names) / sizeof(char *)))
return;
+ LOGP(DRR, LOGL_INFO, "new state %s -> %s\n",
+ gsm48_rr_state_names[rr->state], gsm48_rr_state_names[state]);
+
+ rr->state = state;
+
if (state == GSM48_RR_ST_IDLE) {
struct msgb *msg, *nmsg;
+ /* release dedicated mode, if any */
+// tx_ph_dm_rel_req(rr->ms);
+ l1ctl_tx_reset_req(rr->ms, L1CTL_RES_T_FULL);
/* free establish message, if any */
rr->rr_est_req = 0;
if (rr->rr_est_msg) {
* leave camping state, so it locks against subsequent
* establishment of dedicated channel, before the
* cell selection process returned to camping state
- * again.
+ * again. (after cell reselection)
*/
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_LEAVE_IDLE);
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_RET_IDLE);
if (!nmsg)
return;
gsm322_c_event(rr->ms, nmsg);
msgb_free(nmsg);
+ /* reset any BA range */
+ rr->ba_ranges = 0;
}
-
- LOGP(DRR, LOGL_INFO, "new state %s -> %s\n",
- gsm48_rr_state_names[rr->state], gsm48_rr_state_names[state]);
-
- rr->state = state;
}
/*
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
+ if (!msg->l3h) {
+ printf("FIX l3h\n");
+ exit (0);
+ }
rsl_rll_push_l3(msg, msg_type, rr->cd_now.chan_nr,
rr->cd_now.link_id, 1);
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
-#warning HACK!!!!!!
-return gsm48_rcv_rsl(ms, msg);
msgb_enqueue(&rr->rsl_upqueue, msg);
return 0;
/* FIXME: implement this */
LOGP(DRSL, LOGL_NOTICE, "unknown RSLms msg_discr 0x%02x\n",
rslh->msg_discr);
+ msgb_free(msg);
rc = -EINVAL;
break;
}
* timers handling
*/
+/* special timer to ensure that UA is sent before disconnecting channel */
+static void timeout_rr_t_rel_wait(void *arg)
+{
+ struct gsm48_rrlayer *rr = arg;
+
+ LOGP(DRR, LOGL_INFO, "L2 release timer has fired, done waiting\n");
+
+ /* return to idle now */
+ new_rr_state(rr, GSM48_RR_ST_IDLE);
+}
+
+/* 3.4.13.1.1: Timeout of T3110 */
+static void timeout_rr_t3110(void *arg)
+{
+ struct gsm48_rrlayer *rr = arg;
+ struct osmocom_ms *ms = rr->ms;
+ struct msgb *nmsg;
+ uint8_t *mode;
+
+ LOGP(DRR, LOGL_INFO, "timer T3110 has fired, release locally\n");
+
+ new_rr_state(rr, GSM48_RR_ST_REL_PEND);
+
+ /* disconnect the main signalling link */
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return;
+ mode = msgb_put(nmsg, 2);
+ mode[0] = RSL_IE_RELEASE_MODE;
+ mode[1] = 1; /* local release */
+ gsm48_send_rsl(ms, RSL_MT_REL_REQ, nmsg);
+
+ return;
+}
+
static void timeout_rr_t3122(void *arg)
{
LOGP(DRR, LOGL_INFO, "timer T3122 has fired\n");
struct msgb *msg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
struct gsm48_rr_hdr *rrh;
+ LOGP(DSUM, LOGL_INFO, "Requesting channel failed\n");
if (!msg)
return;
rrh = (struct gsm48_rr_hdr *)msg->data;
new_rr_state(rr, GSM48_RR_ST_IDLE);
}
+static void start_rr_t_rel_wait(struct gsm48_rrlayer *rr, int sec, int micro)
+{
+ LOGP(DRR, LOGL_INFO, "starting T_rel_wait with %d seconds\n", sec);
+ rr->t_rel_wait.cb = timeout_rr_t_rel_wait;
+ rr->t_rel_wait.data = rr;
+ bsc_schedule_timer(&rr->t_rel_wait, sec, micro);
+}
+
+static void start_rr_t3110(struct gsm48_rrlayer *rr, int sec, int micro)
+{
+ LOGP(DRR, LOGL_INFO, "starting T3110 with %d seconds\n", sec);
+ rr->t3110.cb = timeout_rr_t3110;
+ rr->t3110.data = rr;
+ bsc_schedule_timer(&rr->t3110, sec, micro);
+}
+
static void start_rr_t3122(struct gsm48_rrlayer *rr, int sec, int micro)
{
LOGP(DRR, LOGL_INFO, "starting T3122 with %d seconds\n", sec);
bsc_schedule_timer(&rr->t3126, sec, micro);
}
+static void stop_rr_t_rel_wait(struct gsm48_rrlayer *rr)
+{
+ if (bsc_timer_pending(&rr->t_rel_wait)) {
+ LOGP(DRR, LOGL_INFO, "stopping pending timer T_rel_wait\n");
+ bsc_del_timer(&rr->t_rel_wait);
+ }
+}
+
+static void stop_rr_t3110(struct gsm48_rrlayer *rr)
+{
+ if (bsc_timer_pending(&rr->t3110)) {
+ LOGP(DRR, LOGL_INFO, "stopping pending timer T3110\n");
+ bsc_del_timer(&rr->t3110);
+ }
+}
+
static void stop_rr_t3122(struct gsm48_rrlayer *rr)
{
if (bsc_timer_pending(&rr->t3122)) {
/* send chiperhing mode complete */
static int gsm48_rr_tx_cip_mode_cpl(struct osmocom_ms *ms, uint8_t cr)
{
- struct gsm_support *sup = &ms->support;
+ struct gsm_settings *set = &ms->settings;
struct msgb *nmsg;
struct gsm48_hdr *gh;
uint8_t buf[11], *tlv;
/* MI */
if (cr) {
- gsm48_generate_mid_from_imsi(buf, sup->imeisv);
+ gsm48_generate_mid_from_imsi(buf, set->imeisv);
tlv = msgb_put(nmsg, 2 + buf[1]);
memcpy(tlv, buf, 2 + buf[1]);
}
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm_support *sup = &ms->support;
- if (rr->arfcn >= 512 && rr->arfcn <= 885)
+ if (rr->cd_now.arfcn >= 512 && rr->cd_now.arfcn <= 885)
cm->pwr_lev = sup->pwr_lev_1800;
else
cm->pwr_lev = sup->pwr_lev_900;
*/
/* temporary timer until we have time control over channnel request */
+/* TODO: turn this into a channel activation timeout, later */
#define RSL_MT_CHAN_CNF 0x19
#include <osmocom/l1ctl.h>
-static void temp_rach_to(void *arg)
+int gsm48_rr_rach_conf(struct osmocom_ms *ms, uint32_t fn)
{
- struct gsm48_rrlayer *rr = arg;
- struct osmocom_ms *ms = rr->ms;
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
struct msgb *msg = msgb_alloc_headroom(23+10, 10, "LAPDm RR");
- struct abis_rsl_rll_hdr *rllh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rllh));
+ struct abis_rsl_rll_hdr *rllh =
+ (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rllh));
+
+ if (!rr->wait_assign) {
+ LOGP(DRR, LOGL_INFO, "RACH confirm ignored, not waiting for "
+ "assignment.\n");
+ return 0;
+ }
+ LOGP(DRR, LOGL_INFO, "RACH confirm framenr=%u\n", fn);
+ rr->cr_hist[0].valid = 2;
+ rr->cr_hist[0].fn = fn;
rllh->c.msg_type = RSL_MT_CHAN_CNF;
+ msg->l2h = (unsigned char *)rllh;
gsm48_rcv_rsl(ms, msg);
- return;
+ return 0;
}
-/* send channel request burst message */
-static int gsm48_rr_tx_chan_req(struct osmocom_ms *ms, int cause, int paging)
+/* start random access */
+static int gsm48_rr_chan_req(struct osmocom_ms *ms, int cause, int paging)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = cs->si;
struct msgb *nmsg;
- struct l1ctl_info_ul *nul;
- struct l1ctl_rach_req *nra;
struct gsm48_rr_hdr *nrrh;
- uint8_t chan_req, chan_req_val, chan_req_mask;
- int t;
+ uint8_t chan_req_val, chan_req_mask;
+ int rc;
+
+ LOGP(DSUM, LOGL_INFO, "Establish radio link due to %s request\n",
+ (paging) ? "paging" : "mobility management");
/* ignore paging, if not camping */
- if (paging && cs->state != GSM322_C3_CAMPED_NORMALLY) {
- return -EBUSY;
+ if (paging
+ && (!cs->selected || (cs->state != GSM322_C3_CAMPED_NORMALLY
+ && cs->state != GSM322_C7_CAMPED_ANY_CELL))) {
+ LOGP(DRR, LOGL_INFO, "Paging, but not camping, ignore.\n");
+ return -EINVAL;
}
/* tell cell selection process to leave idle mode
nmsg = gsm322_msgb_alloc(GSM322_EVENT_LEAVE_IDLE);
if (!nmsg)
return -ENOMEM;
- gsm322_c_event(ms, nmsg);
+ rc = gsm322_c_event(ms, nmsg);
msgb_free(nmsg);
+ if (rc) {
+ if (paging)
+ return rc;
+ LOGP(DRR, LOGL_INFO, "Failed to leave IDLE mode.\n");
+ goto undefined;
+ }
/* 3.3.1.1.2 */
new_rr_state(rr, GSM48_RR_ST_CONN_PEND);
- /* number of retransmissions (without first transmission) */
- rr->n_chan_req = s->max_retrans;
+ /* number of retransmissions (with first transmission) */
+ rr->n_chan_req = s->max_retrans + 1;
+#warning HACK: always request SDCCH for test
+cause = RR_EST_CAUSE_LOC_UPD;
/* generate CHAN REQ (9.1.8) */
switch (cause) {
case RR_EST_CAUSE_EMERGENCY:
LOGP(DRR, LOGL_INFO, "CHANNEL REQUEST: with unknown "
"establishment cause: %d\n", cause);
+ undefined:
+ LOGP(DSUM, LOGL_INFO, "Requesting channel failed\n");
+
nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
if (!nmsg)
return -ENOMEM;
return -EINVAL;
}
- rr->wait_assign = 1;
-
- /* create and send RACH msg */
-#ifdef TODO
- nmsg = gsm48_rsl_msgb_alloc();
-#else
- nmsg = msgb_alloc_headroom(64, 48, "RAND_ACC");
- struct l1ctl_hdr *l1h;
- nmsg->l1h = msgb_put(nmsg, sizeof(*l1h));
- l1h = (struct l1ctl_hdr *) nmsg->l1h;
- l1h->msg_type = L1CTL_RACH_REQ;
- if (!nmsg)
- return -ENOMEM;
- nul = (struct l1ctl_info_ul *) msgb_put(nmsg, sizeof(*nul));
-#endif
- nra = (struct l1ctl_rach_req *) msgb_put(nmsg, sizeof(*nra));
-
- chan_req = random();
- chan_req &= chan_req_mask;
- chan_req |= chan_req_val;
- nra->ra = chan_req;
- t = s->tx_integer;
- if (t < 8)
- t = 8;
-#ifdef TODO
- at this point we require chan req to be sent at a given delay
- also we require a confirm from radio part
- nra->delay = random() % t;
-#else
- rr->temp_rach_ti.cb = temp_rach_to;
- rr->temp_rach_ti.data = rr;
- bsc_schedule_timer(&rr->temp_rach_ti, 0, 900000);
-#endif
-
- /* store */
+ /* store value, mask and history */
rr->chan_req_val = chan_req_val;
rr->chan_req_mask = chan_req_mask;
- rr->cr_hist[3] = -1;
- rr->cr_hist[2] = -1;
- rr->cr_hist[1] = chan_req;
+ rr->cr_hist[2].valid = 0;
+ rr->cr_hist[1].valid = 0;
+ rr->cr_hist[0].valid = 0;
-#ifdef TODO
- add layer 1 conrols to RSL...
- return gsm48_send_rsl(ms, RSL_MT_CHAN_REQ, nmsg);
-#else
- return osmo_send_l1(ms, nmsg);
-#endif
+ /* if channel is already active somehow */
+ if (cs->ccch_state == GSM322_CCCH_ST_DATA)
+ return gsm48_rr_tx_rand_acc(ms, NULL);
+
+ return 0;
}
-/* send next channel request in conn pend state */
-static int gsm48_rr_rand_acc_cnf(struct osmocom_ms *ms, struct msgb *msg)
+/* send first/next channel request in conn pend state */
+int gsm48_rr_tx_rand_acc(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm322_cellsel *cs = &ms->cellsel;
+ struct gsm48_sysinfo *s = &ms->cellsel.sel_si;
struct msgb *nmsg;
struct l1ctl_info_ul *nul;
struct l1ctl_rach_req *nra;
int slots;
uint8_t chan_req;
- LOGP(DRR, LOGL_INFO, "RANDOM ACCESS confirm (requests left %d)\n",
+ if (cs->ccch_state != GSM322_CCCH_ST_DATA) {
+ LOGP(DRR, LOGL_INFO, "CCCH channel activation failed.\n");
+
+ if (rr->rr_est_req) {
+ struct msgb *msg =
+ gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
+ struct gsm48_rr_hdr *rrh;
+
+ LOGP(DSUM, LOGL_INFO, "Requesting channel failed\n");
+ if (!msg)
+ return -ENOMEM;
+ rrh = (struct gsm48_rr_hdr *)msg->data;
+ rrh->cause = RR_REL_CAUSE_RA_FAILURE;
+ gsm48_rr_upmsg(ms, msg);
+ }
+
+ new_rr_state(rr, GSM48_RR_ST_IDLE);
+
+ return 0;
+ }
+
+ if (rr->state == GSM48_RR_ST_IDLE) {
+ LOGP(DRR, LOGL_INFO, "MM already released RR.\n");
+
+ return 0;
+ }
+
+ LOGP(DRR, LOGL_INFO, "RANDOM ACCESS (requests left %d)\n",
rr->n_chan_req);
if (!rr->n_chan_req) {
}
rr->n_chan_req--;
- /* table 3.1 */
- switch(s->tx_integer) {
- case 3: case 8: case 14: case 50:
- if (s->ccch_conf != 1) /* not combined CCCH */
- slots = 55;
- else
- slots = 41;
- case 4: case 9: case 16:
- if (s->ccch_conf != 1)
- slots = 76;
- else
- slots = 52;
- case 5: case 10: case 20:
- if (s->ccch_conf != 1)
- slots = 109;
- else
- slots = 58;
- case 6: case 11: case 25:
- if (s->ccch_conf != 1)
- slots = 163;
- else
- slots = 86;
- default:
- if (s->ccch_conf != 1)
- slots = 217;
- else
- slots = 115;
+ if (!rr->wait_assign) {
+ /* first random acces, without delay of slots */
+ slots = 0;
+ rr->wait_assign = 1;
+ } else {
+ /* subsequent random acces, with slots from table 3.1 */
+ switch(s->tx_integer) {
+ case 3: case 8: case 14: case 50:
+ if (s->ccch_conf != 1) /* not combined CCCH */
+ slots = 55;
+ else
+ slots = 41;
+ break;
+ case 4: case 9: case 16:
+ if (s->ccch_conf != 1)
+ slots = 76;
+ else
+ slots = 52;
+ break;
+ case 5: case 10: case 20:
+ if (s->ccch_conf != 1)
+ slots = 109;
+ else
+ slots = 58;
+ break;
+ case 6: case 11: case 25:
+ if (s->ccch_conf != 1)
+ slots = 163;
+ else
+ slots = 86;
+ break;
+ default:
+ if (s->ccch_conf != 1)
+ slots = 217;
+ else
+ slots = 115;
+ break;
+ }
}
/* resend chan_req with new randiom */
chan_req &= rr->chan_req_mask;
chan_req |= rr->chan_req_val;
nra->ra = chan_req;
-#ifdef TODO
- at this point we require chan req to be sent at a given delay
- also we require a confirm from radio part
- nra->delay = (random() % s->tx_integer) + slots;
-
- LOGP(DRR, LOGL_INFO, "RANDOM ACCESS (ra 0x%02x delay %d)\n", nra->ra,
- nra->delay);
-#else
- rr->temp_rach_ti.cb = temp_rach_to;
- rr->temp_rach_ti.data = rr;
- bsc_schedule_timer(&rr->temp_rach_ti, 0, 900000);
+#warning TODO
+ nra->mf_off = 1; // (random() % s->tx_integer) + slots;
+ nra->fn51 = (s->ccch_conf == 1) ? 27 : 50;
- LOGP(DRR, LOGL_INFO, "RANDOM ACCESS (ra 0x%02x)\n", nra->ra);
-#endif
+ LOGP(DRR, LOGL_INFO, "RANDOM ACCESS (Tx-integer %d combined %s "
+ "S(lots) %d ra 0x%02x offset %d)\n", s->tx_integer,
+ (s->ccch_conf == 1) ? "yes": "no", slots, nra->ra, nra->mf_off);
/* shift history and store */
- rr->cr_hist[3] = rr->cr_hist[2];
- rr->cr_hist[2] = rr->cr_hist[1];
- rr->cr_hist[1] = chan_req;
+ memcpy(&(rr->cr_hist[2]), &(rr->cr_hist[1]),
+ sizeof(struct gsm48_cr_hist));
+ memcpy(&(rr->cr_hist[1]), &(rr->cr_hist[0]),
+ sizeof(struct gsm48_cr_hist));
+ rr->cr_hist[0].valid = 1;
+ rr->cr_hist[0].chan_req = chan_req;
#ifdef TODO
add layer 1 conrols to RSL...
return gsm48_send_rsl(ms, RSL_MT_CHAN_REQ, nmsg);
#else
+//#warning disabled!
return osmo_send_l1(ms, nmsg);
#endif
}
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;
+ 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;
+ w[2] = (r->w2_hi << 2) | r->w2_lo;
if (len >= 6)
- w[3] = (r->w3_hi << 2) || r->w3_lo;
+ w[3] = (r->w3_hi << 2) | r->w3_lo;
if (len >= 7)
- w[4] = (r->w4_hi << 1) || r->w4_lo;
+ 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;
+ w[7] = (r->w7_hi << 6) | r->w7_lo;
if (len >= 10)
- w[8] = (r->w8_hi << 4) || r->w8_lo;
+ w[8] = (r->w8_hi << 4) | r->w8_lo;
if (len >= 11)
- w[9] = (r->w9_hi << 2) || r->w9_lo;
+ 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;
+ w[12] = (r->w12_hi << 4) | r->w12_lo;
if (len >= 14)
- w[13] = (r->w13_hi << 2) || r->w13_lo;
+ 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;
+ w[16] = (r->w16_hi << 3) | r->w16_lo;
if (len >= 16)
w[17] = r->w17;
- if (w[0])
- f[w[0]].mask |= frqt;
+ f[w[0]].mask |= frqt;
if (w[1])
f[(w[0] + w[1]) % 1024].mask |= frqt;
if (w[2])
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;
+ 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;
+ w[4] = (r->w4_hi << 5) | r->w4_lo;
if (len >= 7)
- w[5] = (r->w5_hi << 3) || r->w5_lo;
+ w[5] = (r->w5_hi << 3) | r->w5_lo;
if (len >= 8)
- w[6] = (r->w6_hi << 1) || r->w6_lo;
+ 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;
+ w[8] = (r->w8_hi << 4) | r->w8_lo;
if (len >= 10)
- w[9] = (r->w9_hi << 1) || r->w9_lo;
+ 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;
+ w[11] = (r->w11_hi << 3) | r->w11_lo;
if (len >= 11)
w[12] = r->w12;
if (len >= 12)
if (len >= 13)
w[14] = r->w15;
if (len >= 13)
- w[15] = (r->w14_hi << 2) || r->w14_lo;
+ w[15] = (r->w14_hi << 2) | r->w14_lo;
if (len >= 14)
- w[16] = (r->w16_hi << 3) || r->w16_lo;
+ 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;
+ w[19] = (r->w18_hi << 3) | r->w18_lo;
if (len >= 16)
- w[20] = (r->w20_hi << 3) || r->w20_lo;
+ w[20] = (r->w20_hi << 3) | r->w20_lo;
if (len >= 16)
w[21] = r->w21;
- if (w[0])
- f[w[0]].mask |= frqt;
+ f[w[0]].mask |= frqt;
if (w[1])
f[(w[0] + w[1]) % 1024].mask |= frqt;
if (w[2])
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[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;
+ w[3] = (r->w3_hi << 4) | r->w3_lo;
if (len >= 6)
- w[4] = (r->w4_hi << 1) || r->w4_lo;
+ 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;
+ w[6] = (r->w6_hi << 3) | r->w6_lo;
if (len >= 7)
w[7] = r->w7;
if (len >= 8)
if (len >= 12)
w[17] = r->w17;
if (len >= 13)
- w[18] = (r->w18_hi << 1) || r->w18_lo;
+ 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;
+ w[21] = (r->w21_hi << 2) | r->w21_lo;
if (len >= 14)
w[22] = r->w22;
if (len >= 14)
if (len >= 15)
w[25] = r->w25;
if (len >= 16)
- w[26] = (r->w26_hi << 1) || r->w26_lo;
+ 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;
+ f[w[0]].mask |= frqt;
if (w[1])
f[(w[0] + w[1]) % 1024].mask |= frqt;
if (w[2])
if (len < 3)
return -EINVAL;
- orig = (r->orig_arfcn_hi << 9) || (r->orig_arfcn_mid << 1) || r->orig_arfcn_lo;
+ 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;
+ f[(orig + i) % 1024].mask |= frqt;
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)
+ uint8_t *ma, uint8_t len, uint16_t *hopping, uint8_t *hopp_len, int si4)
{
int i, j = 0;
uint16_t f[len << 3];
return -EINVAL;
/* tabula rasa */
- s->hopp_len = 0;
- for (i = 0; i < 1024; i++)
- s->freq[i].mask &= ~FREQ_TYPE_HOPP;
+ *hopp_len = 0;
+ if (si4) {
+ for (i = 0; i < 1024; i++)
+ s->freq[i].mask &= ~FREQ_TYPE_HOPP;
+ }
/* generating list of all frequencies (1..1023,0) */
for (i = 1; i <= 1024; i++) {
if ((s->freq[i & 1023].mask & FREQ_TYPE_SERV)) {
+ LOGP(DRR, LOGL_INFO, "Serving cell ARFCN #%d: %d\n",
+ j, i & 1023);
f[j++] = i & 1023;
if (j == (len << 3))
break;
for (i = 0; i < (len << 3); i++) {
/* if bit is set, this frequency index is used for hopping */
if ((ma[len - 1 - (i >> 3)] & (1 << (i & 7)))) {
+ LOGP(DRR, LOGL_INFO, "Hopping ARFCN: %d (bit %d)\n",
+ i, f[i]);
/* index higher than entries in list ? */
if (i >= j) {
LOGP(DRR, LOGL_NOTICE, "Mobile Allocation "
i + 1, j);
break;
}
- s->hopping[s->hopp_len++] = f[i];
- s->freq[f[i]].mask |= FREQ_TYPE_HOPP;
+ hopping[(*hopp_len)++] = f[i];
+ if (si4)
+ s->freq[f[i]].mask |= FREQ_TYPE_HOPP;
}
}
static int gsm48_decode_si3_rest(struct gsm48_sysinfo *s, uint8_t *si,
uint8_t len)
{
+ struct bitvec bv;
+
+ memset(&bv, 0, sizeof(bv));
+ bv.data_len = len;
+ bv.data = si;
+
+ /* Optional Selection Parameters */
+ if (bitvec_get_bit_high(&bv) == H) {
+ s->sp = 1;
+ s->sp_cbq = bitvec_get_uint(&bv, 1);
+ s->sp_cro = bitvec_get_uint(&bv, 6);
+ s->sp_to = bitvec_get_uint(&bv, 3);
+ s->sp_pt = bitvec_get_uint(&bv, 5);
+ }
+ /* Optional Power Offset */
+ if (bitvec_get_bit_high(&bv) == H) {
+ s->po = 1;
+ s->po_value = bitvec_get_uint(&bv, 3);
+ }
+ /* System Onformation 2ter Indicator */
+ if (bitvec_get_bit_high(&bv) == H)
+ s->si2ter_ind = 1;
+ /* Early Classark Sending Control */
+ if (bitvec_get_bit_high(&bv) == H)
+ s->ecsm = 1;
+ /* Scheduling if and where */
+ if (bitvec_get_bit_high(&bv) == H) {
+ s->sched = 1;
+ s->sched_where = bitvec_get_uint(&bv, 3);
+ }
+ /* GPRS Indicator */
+ s->gi_ra_colour = bitvec_get_uint(&bv, 3);
+ s->gi_si13_pos = bitvec_get_uint(&bv, 1);
return 0;
}
static int gsm48_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;
+ struct gsm48_sysinfo *s = ms->cellsel.si;
int payload_len = msgb_l3len(msg) - sizeof(*si);
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 1 "
+ "ignored\n");
+ return -EINVAL;
+ }
+
if (payload_len < 0) {
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 1 "
"message.\n");
static int gsm48_rr_rx_sysinfo2(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_system_information_type_2 *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = ms->cellsel.si;
int payload_len = msgb_l3len(msg) - sizeof(*si);
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 2 "
+ "ignored\n");
+ return -EINVAL;
+ }
+
if (payload_len < 0) {
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 2 "
"message.\n");
static int gsm48_rr_rx_sysinfo2bis(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_system_information_type_2bis *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = ms->cellsel.si;
int payload_len = msgb_l3len(msg) - sizeof(*si);
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 2bis"
+ " ignored\n");
+ return -EINVAL;
+ }
+
if (payload_len < 0) {
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 2bis "
"message.\n");
static int gsm48_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;
+ struct gsm48_sysinfo *s = ms->cellsel.si;
int payload_len = msgb_l3len(msg) - sizeof(*si);
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 2ter"
+ " ignored\n");
+ return -EINVAL;
+ }
+
if (payload_len < 0) {
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 2ter "
"message.\n");
static int gsm48_rr_rx_sysinfo3(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_system_information_type_3 *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm322_cellsel *cs = &ms->cellsel;
+ struct gsm48_sysinfo *s = cs->si;
int payload_len = msgb_l3len(msg) - sizeof(*si);
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 3 "
+ "ignored\n");
+ return -EINVAL;
+ }
+
if (payload_len < 0) {
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 3 "
"message.\n");
if (payload_len >= 4)
gsm48_decode_si3_rest(s, si->rest_octets, payload_len);
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 3 (mcc %03d mnc %02d "
- "lac 0x%04x)\n", s->mcc, s->mnc, s->lac);
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 3 (mcc %s mnc %s "
+ "lac 0x%04x)\n", gsm_print_mcc(s->mcc),
+ gsm_print_mnc(s->mnc), s->lac);
s->si3 = 1;
+ if (cs->ccch_mode == CCCH_MODE_NONE) {
+ cs->ccch_mode = (s->ccch_conf == 1) ? CCCH_MODE_COMBINED :
+ CCCH_MODE_NON_COMBINED;
+ LOGP(DRR, LOGL_NOTICE, "Changing CCCH_MODE to %d\n",
+ cs->ccch_mode);
+ l1ctl_tx_ccch_mode_req(ms, cs->ccch_mode);
+ }
+
return gsm48_send_sysinfo(ms, si->header.system_information);
}
{
/* NOTE: pseudo length is not in this structure, so we skip */
struct gsm48_system_information_type_4 *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = ms->cellsel.si;
int payload_len = msgb_l3len(msg) - sizeof(*si);
uint8_t *data = si->data;
struct gsm48_chan_desc *cd;
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 4 "
+ "ignored\n");
+ return -EINVAL;
+ }
+
if (payload_len < 0) {
short_read:
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 4 "
return -EINVAL;
}
+ if (!s->si1) {
+ LOGP(DRR, LOGL_NOTICE, "Ignoring SYSTEM INFORMATION 4 "
+ "until SI 1 is received.\n");
+ return -EBUSY;
+ }
+
if (!memcmp(si, s->si4_msg, MIN(msgb_l3len(msg), sizeof(s->si4_msg))))
return 0;
memcpy(s->si4_msg, si, MIN(msgb_l3len(msg), sizeof(s->si4_msg)));
if (payload_len >= 1 && data[0] == GSM48_IE_CBCH_MOB_AL) {
if (payload_len < 1 || payload_len < 2 + data[1])
goto short_read;
- gsm48_decode_mobile_alloc(s, data + 2, si->data[1]);
+ gsm48_decode_mobile_alloc(s, data + 2, si->data[1], s->hopping,
+ &s->hopp_len, 1);
payload_len -= 2 + data[1];
data += 2 + data[1];
}
if (payload_len > 0)
gsm48_decode_si4_rest(s, data, payload_len);
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 4 (mcc %03d mnc %02d "
- "lac 0x%04x)\n", s->mcc, s->mnc, s->lac);
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 4 (mcc %s mnc %s "
+ "lac 0x%04x)\n", gsm_print_mcc(s->mcc),
+ gsm_print_mnc(s->mnc), s->lac);
s->si4 = 1;
{
/* NOTE: pseudo length is not in this structure, so we skip */
struct gsm48_system_information_type_5 *si = msgb_l3(msg) + 1;
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = ms->cellsel.si;
int payload_len = msgb_l3len(msg) - sizeof(*si) - 1;
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 5 "
+ "ignored\n");
+ return -EINVAL;
+ }
+
if (payload_len < 0) {
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 5 "
"message.\n");
{
/* NOTE: pseudo length is not in this structure, so we skip */
struct gsm48_system_information_type_5bis *si = msgb_l3(msg) + 1;
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = ms->cellsel.si;
int payload_len = msgb_l3len(msg) - sizeof(*si) - 1;
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 5bis"
+ " ignored\n");
+ return -EINVAL;
+ }
+
if (payload_len < 0) {
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 5bis "
"message.\n");
{
/* NOTE: pseudo length is not in this structure, so we skip */
struct gsm48_system_information_type_5ter *si = msgb_l3(msg) + 1;
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = ms->cellsel.si;
int payload_len = msgb_l3len(msg) - sizeof(*si) - 1;
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 5ter"
+ " ignored\n");
+ return -EINVAL;
+ }
+
if (payload_len < 0) {
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 5ter "
"message.\n");
{
/* NOTE: pseudo length is not in this structure, so we skip */
struct gsm48_system_information_type_6 *si = msgb_l3(msg) + 1;
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = ms->cellsel.si;
int payload_len = msgb_l3len(msg) - sizeof(*si) - 1;
+ if (!s) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, SYSTEM INFORMATION 6 "
+ "ignored\n");
+ return -EINVAL;
+ }
+
if (payload_len < 0) {
LOGP(DRR, LOGL_NOTICE, "Short read of SYSTEM INFORMATION 6 "
"message.\n");
if (payload_len >= 4)
gsm48_decode_si6_rest(s, si->rest_octets, payload_len);
- LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 6 (mcc %03d mnc %02d "
- "lac 0x%04x)\n", s->mcc, s->mnc, s->lac);
+ LOGP(DRR, LOGL_INFO, "New SYSTEM INFORMATION 6 (mcc %s mnc %s "
+ "lac 0x%04x)\n", gsm_print_mcc(s->mcc),
+ gsm_print_mnc(s->mnc), s->lac);
s->si6 = 1;
memcpy(&tmsi, mi+2, 4);
if (ms->subscr.tmsi == ntohl(tmsi)
&& ms->subscr.tmsi_valid) {
- LOGP(DRR, LOGL_INFO, "TMSI %08x matches\n", ntohl(tmsi));
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n",
+ ntohl(tmsi));
return 1;
} else
- LOGP(DRR, LOGL_INFO, "TMSI %08x (not for us)\n",
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x (not for us)\n",
ntohl(tmsi));
break;
case GSM_MI_TYPE_IMSI:
gsm48_mi_to_string(imsi, sizeof(imsi), mi + 1, mi[0]);
if (!strcmp(imsi, ms->subscr.imsi)) {
- LOGP(DRR, LOGL_INFO, "IMSI %s matches\n", imsi);
+ LOGP(DPAG, LOGL_INFO, "IMSI %s matches\n", imsi);
return 1;
} else
- LOGP(DRR, LOGL_INFO, "IMSI %s (not for us)\n", imsi);
+ LOGP(DPAG, LOGL_INFO, "IMSI %s (not for us)\n", imsi);
break;
default:
- LOGP(DRR, LOGL_NOTICE, "Paging with unsupported MI type %d.\n",
+ LOGP(DPAG, LOGL_NOTICE, "Paging with unsupported MI type %d.\n",
mi_type);
}
int chan_1, chan_2;
uint8_t *mi;
+ /* empty paging request */
+ if (payload_len >= 2 && (pa->data[1] & GSM_MI_TYPE_MASK) == 0)
+ return 0;
+
/* 3.3.1.1.2: ignore paging while not camping on a cell */
- if (rr->state != GSM48_RR_ST_IDLE
- && cs->state != GSM322_C3_CAMPED_NORMALLY) {
- LOGP(DRR, LOGL_INFO, "PAGING ignored, we are not camping "
- "normally.\n");
+ if (rr->state != GSM48_RR_ST_IDLE || !cs->selected
+ || (cs->state != GSM322_C3_CAMPED_NORMALLY
+ && cs->state != GSM322_C7_CAMPED_ANY_CELL)) {
+ LOGP(DRR, LOGL_INFO, "PAGING ignored, we are not camping.\n");
+
return 0;
}
+ LOGP(DPAG, LOGL_INFO, "PAGING REQUEST 1\n");
if (payload_len < 2) {
short_read:
LOGP(DRR, LOGL_NOTICE, "Short read of PAGING REQUEST 1 "
"message.\n");
+
return -EINVAL;
}
chan_1 = pa->cneed1;
chan_2 = pa->cneed2;
/* first MI */
- mi = pa->data + 1;
+ mi = pa->data;
if (payload_len < mi[0] + 1)
goto short_read;
if (gsm_match_mi(ms, mi) > 0)
- return gsm48_rr_tx_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
/* second MI */
payload_len -= mi[0] + 1;
mi = pa->data + mi[0] + 1;
if (payload_len < mi[1] + 2)
goto short_read;
if (gsm_match_mi(ms, mi + 1) > 0)
- return gsm48_rr_tx_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
return 0;
}
int chan_1, chan_2, chan_3;
/* 3.3.1.1.2: ignore paging while not camping on a cell */
- if (rr->state != GSM48_RR_ST_IDLE
- && cs->state != GSM322_C3_CAMPED_NORMALLY) {
- LOGP(DRR, LOGL_INFO, "PAGING ignored, we are not camping "
- "normally.\n");
+ if (rr->state != GSM48_RR_ST_IDLE || !cs->selected
+ || (cs->state != GSM322_C3_CAMPED_NORMALLY
+ && cs->state != GSM322_C7_CAMPED_ANY_CELL)) {
+ LOGP(DRR, LOGL_INFO, "PAGING ignored, we are not camping.\n");
+
return 0;
}
+ LOGP(DPAG, LOGL_INFO, "PAGING REQUEST 2\n");
if (payload_len < 0) {
short_read:
LOGP(DRR, LOGL_NOTICE, "Short read of PAGING REQUEST 2 "
"message .\n");
+
return -EINVAL;
}
chan_2 = pa->cneed2;
/* first MI */
if (ms->subscr.tmsi == ntohl(pa->tmsi1)
- && ms->subscr.tmsi_valid)
- return gsm48_rr_tx_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
+ && ms->subscr.tmsi_valid) {
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi1));
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
+ } else
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x (not for us)\n",
+ ntohl(pa->tmsi1));
/* second MI */
if (ms->subscr.tmsi == ntohl(pa->tmsi2)
- && ms->subscr.tmsi_valid)
- return gsm48_rr_tx_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
+ && ms->subscr.tmsi_valid) {
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi2));
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
+ } else
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x (not for us)\n",
+ ntohl(pa->tmsi2));
/* third MI */
mi = pa->data;
if (payload_len < 2)
goto short_read;
chan_3 = mi[mi[1] + 2] & 0x03; /* channel needed */
if (gsm_match_mi(ms, mi + 1) > 0)
- return gsm48_rr_tx_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1);
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1);
return 0;
}
int chan_1, chan_2, chan_3, chan_4;
/* 3.3.1.1.2: ignore paging while not camping on a cell */
- if (rr->state != GSM48_RR_ST_IDLE
- && cs->state != GSM322_C3_CAMPED_NORMALLY) {
- LOGP(DRR, LOGL_INFO, "PAGING ignored, we are not camping "
- "normally.\n");
+ if (rr->state != GSM48_RR_ST_IDLE || !cs->selected
+ || (cs->state != GSM322_C3_CAMPED_NORMALLY
+ && cs->state != GSM322_C7_CAMPED_ANY_CELL)) {
+ LOGP(DRR, LOGL_INFO, "PAGING ignored, we are not camping.\n");
+
return 0;
}
+ LOGP(DPAG, LOGL_INFO, "PAGING REQUEST 3\n");
if (payload_len < 0) { /* must include "channel needed", part of *pa */
LOGP(DRR, LOGL_NOTICE, "Short read of PAGING REQUEST 3 "
"message .\n");
+
return -EINVAL;
}
chan_4 = pa->cneed4;
/* first MI */
if (ms->subscr.tmsi == ntohl(pa->tmsi1)
- && ms->subscr.tmsi_valid)
- return gsm48_rr_tx_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
+ && ms->subscr.tmsi_valid) {
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi1));
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_1], 1);
+ } else
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x (not for us)\n",
+ ntohl(pa->tmsi1));
/* second MI */
if (ms->subscr.tmsi == ntohl(pa->tmsi2)
- && ms->subscr.tmsi_valid)
- return gsm48_rr_tx_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
+ && ms->subscr.tmsi_valid) {
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi2));
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_2], 1);
+ } else
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x (not for us)\n",
+ ntohl(pa->tmsi2));
/* thrid MI */
if (ms->subscr.tmsi == ntohl(pa->tmsi3)
- && ms->subscr.tmsi_valid)
- return gsm48_rr_tx_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1);
+ && ms->subscr.tmsi_valid) {
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi3));
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_3], 1);
+ } else
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x (not for us)\n",
+ ntohl(pa->tmsi3));
/* fourth MI */
if (ms->subscr.tmsi == ntohl(pa->tmsi4)
- && ms->subscr.tmsi_valid)
- return gsm48_rr_tx_chan_req(ms, gsm48_rr_chan2cause[chan_4], 1);
+ && ms->subscr.tmsi_valid) {
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x matches\n", ntohl(pa->tmsi4));
+ return gsm48_rr_chan_req(ms, gsm48_rr_chan2cause[chan_4], 1);
+ } else
+ LOGP(DPAG, LOGL_INFO, "TMSI %08x (not for us)\n",
+ ntohl(pa->tmsi4));
return 0;
}
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
int i;
+ struct gsm_time tm;
+ uint8_t ia_t1, ia_t2, ia_t3;
for (i = 0; i < 3; i++) {
- if (rr->cr_hist[i] >= 0
- && ref->ra == rr->cr_hist[i]) {
- LOGP(DRR, LOGL_INFO, "request %02x matches\n", ref->ra);
- // todo: match timeslot
- return 1;
+ /* filter confirmed RACH requests only */
+ if (rr->cr_hist[i].valid == 2
+ && ref->ra == rr->cr_hist[i].chan_req) {
+ ia_t1 = ref->t1;
+ ia_t2 = ref->t2;
+ ia_t3 = (ref->t3_high << 3) | ref->t3_low;
+ gsm_fn2gsmtime(&tm, rr->cr_hist[i].fn);
+ if (ia_t1 == (tm.t1 & 0x1f) && ia_t2 == tm.t2
+ && ia_t3 == tm.t3) {
+ LOGP(DRR, LOGL_INFO, "request %02x matches "
+ "(fn=%d,%d,%d)\n", ref->ra, ia_t1,
+ ia_t2, ia_t3);
+ return 1;
+ } else
+ LOGP(DRR, LOGL_INFO, "request %02x matches "
+ "but not frame number (IMM.ASS "
+ "fn=%d,%d,%d != RACH fn=%d,%d,%d)\n",
+ ref->ra, ia_t1, ia_t2, ia_t3,
+ tm.t1 & 0x1f, tm.t2, tm.t3);
}
}
return 0;
}
-/* 9.1.3 sending ASSIGNMENT COMPLETE */
-static int gsm48_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause)
+/* 9.1.18 IMMEDIATE ASSIGNMENT is received */
+static int gsm48_rr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
{
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm48_ass_cpl *ac;
-
- LOGP(DRR, LOGL_INFO, "ASSIGNMENT COMPLETE (cause #%d)\n", cause);
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct gsm48_imm_ass *ia = msgb_l3(msg);
+ int ma_len = msgb_l3len(msg) - sizeof(*ia);
+ uint8_t ch_type, ch_subch, ch_ts;
+ struct gsm48_rr_cd cd;
+ uint8_t *st, st_len;
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
- ac = (struct gsm48_ass_cpl *) msgb_put(nmsg, sizeof(*ac));
-
- gh->proto_discr = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_ASS_COMPL;
-
- /* RR_CAUSE */
- ac->rr_cause = cause;
-
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
-}
-
-/* 9.1.4 sending ASSIGNMENT FAILURE */
-static int gsm48_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm48_ass_fail *af;
-
- LOGP(DRR, LOGL_INFO, "ASSIGNMENT FAILURE (cause #%d)\n", cause);
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
- af = (struct gsm48_ass_fail *) msgb_put(nmsg, sizeof(*af));
-
- gh->proto_discr = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_ASS_COMPL;
-
- /* RR_CAUSE */
- af->rr_cause = cause;
-
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
-}
-
-/* 9.1.18 IMMEDIATE ASSIGNMENT is received */
-static int gsm48_rr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_rrlayer *rr = &ms->rrlayer;
- struct gsm48_imm_ass *ia = msgb_l3(msg);
- int ma_len = msgb_l3len(msg) - sizeof(*ia);
- uint8_t ch_type, ch_subch, ch_ts;
- struct gsm48_rr_cd cd;
- uint8_t *st, st_len;
-
- memset(&cd, 0, sizeof(cd));
+ memset(&cd, 0, sizeof(cd));
if (ma_len < 0 /* mobile allocation IE must be included */
|| ia->mob_alloc_len > ma_len) { /* short read of IE */
gsm48_decode_start_time(&cd, (struct gsm48_start_time *)(st+1));
/* decode channel description */
- rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts);
+ LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT:\n");
+ cd.chan_nr = ia->chan_desc.chan_nr;
+ rsl_dec_chan_nr(cd.chan_nr, &ch_type, &ch_subch, &ch_ts);
if (ia->chan_desc.h0.h) {
cd.h = 1;
gsm48_decode_chan_h1(&ia->chan_desc, &cd.tsc, &cd.maio,
&cd.hsn);
- LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT (ra=0x%02x, "
- "chan_nr=0x%02x, MAIO=%u, HSN=%u, TS=%u, SS=%u, "
- "TSC=%u)\n", ia->req_ref.ra, ia->chan_desc.chan_nr,
- cd.maio, cd.hsn, ch_ts, ch_subch, cd.tsc);
+ LOGP(DRR, LOGL_INFO, " (ta %d/%dm ra 0x%02x chan_nr 0x%02x "
+ "MAIO %u HSN %u TS %u SS %u TSC %u)\n",
+ ia->timing_advance,
+ ia->timing_advance * GSM_TA_CM / 100,
+ ia->req_ref.ra, ia->chan_desc.chan_nr, cd.maio,
+ cd.hsn, ch_ts, ch_subch, cd.tsc);
} else {
cd.h = 0;
gsm48_decode_chan_h0(&ia->chan_desc, &cd.tsc, &cd.arfcn);
- LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT (ra=0x%02x, "
- "chan_nr=0x%02x, ARFCN=%u, TS=%u, SS=%u, TSC=%u)\n",
+ LOGP(DRR, LOGL_INFO, " (ta %d/%dm ra 0x%02x chan_nr 0x%02x "
+ "ARFCN %u TS %u SS %u TSC %u)\n",
+ ia->timing_advance,
+ ia->timing_advance * GSM_TA_CM / 100,
ia->req_ref.ra, ia->chan_desc.chan_nr, cd.arfcn,
ch_ts, ch_subch, cd.tsc);
}
/* 3.3.1.1.2: ignore assignment while idle */
if (rr->state != GSM48_RR_ST_CONN_PEND || !rr->wait_assign) {
- LOGP(DRR, LOGL_INFO, "no previous request\n");
+ LOGP(DRR, LOGL_INFO, "Not for us, no request.\n");
return 0;
}
rr->wait_assign = 0;
return gsm48_rr_dl_est(ms);
}
- LOGP(DRR, LOGL_INFO, "does not match our request\n");
+ LOGP(DRR, LOGL_INFO, "Request, but not for us.\n");
return 0;
}
}
/* decode channel description */
- LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT ");
- rsl_dec_chan_nr(ia->chan_desc1.chan_nr, &ch_type, &ch_subch, &ch_ts);
+ LOGP(DRR, LOGL_INFO, "IMMEDIATE ASSIGNMENT EXTENDED:\n");
+ cd2.chan_nr = ia->chan_desc1.chan_nr;
+ rsl_dec_chan_nr(cd1.chan_nr, &ch_type, &ch_subch, &ch_ts);
if (ia->chan_desc1.h0.h) {
cd1.h = 1;
gsm48_decode_chan_h1(&ia->chan_desc1, &cd1.tsc, &cd1.maio,
&cd1.hsn);
- LOGP(DRR, LOGL_INFO, "1(ra=0x%02x, "
- "chan_nr=0x%02x, MAIO=%u, HSN=%u, TS=%u, SS=%u, "
- "TSC=%u)\n", ia->req_ref1.ra, ia->chan_desc1.chan_nr,
- cd1.maio, cd1.hsn, ch_ts, ch_subch, cd1.tsc);
+ LOGP(DRR, LOGL_INFO, " assignment 1 (ta %d/%dm ra 0x%02x "
+ "chan_nr 0x%02x MAIO %u HSN %u TS %u SS %u TSC %u)\n",
+ ia->timing_advance1,
+ ia->timing_advance1 * GSM_TA_CM / 100,
+ ia->req_ref1.ra, ia->chan_desc1.chan_nr, cd1.maio,
+ cd1.hsn, ch_ts, ch_subch, cd1.tsc);
} else {
cd1.h = 0;
gsm48_decode_chan_h0(&ia->chan_desc1, &cd1.tsc, &cd1.arfcn);
- LOGP(DRR, LOGL_INFO, "1(ra=0x%02x, "
- "chan_nr=0x%02x, ARFCN=%u, TS=%u, SS=%u, TSC=%u)\n",
+ LOGP(DRR, LOGL_INFO, " assignment 1 (ta %d/%dm ra 0x%02x "
+ "chan_nr 0x%02x ARFCN %u TS %u SS %u TSC %u)\n",
+ ia->timing_advance1,
+ ia->timing_advance1 * GSM_TA_CM / 100,
ia->req_ref1.ra, ia->chan_desc1.chan_nr, cd1.arfcn,
ch_ts, ch_subch, cd1.tsc);
}
- rsl_dec_chan_nr(ia->chan_desc2.chan_nr, &ch_type, &ch_subch, &ch_ts);
+ cd2.chan_nr = ia->chan_desc2.chan_nr;
+ rsl_dec_chan_nr(cd2.chan_nr, &ch_type, &ch_subch, &ch_ts);
if (ia->chan_desc2.h0.h) {
cd2.h = 1;
- gsm48_decode_chan_h1(&ia->chan_desc2, &cd1.tsc, &cd1.maio,
- &cd1.hsn);
- LOGP(DRR, LOGL_INFO, "2(ra=0x%02x, "
- "chan_nr=0x%02x, MAIO=%u, HSN=%u, TS=%u, SS=%u, "
- "TSC=%u)\n", ia->req_ref2.ra, ia->chan_desc2.chan_nr,
- cd2.maio, cd2.hsn, ch_ts, ch_subch, cd2.tsc);
+ gsm48_decode_chan_h1(&ia->chan_desc2, &cd2.tsc, &cd2.maio,
+ &cd2.hsn);
+ LOGP(DRR, LOGL_INFO, " assignment 2 (ta %d/%dm ra 0x%02x "
+ "chan_nr 0x%02x MAIO %u HSN %u TS %u SS %u TSC %u)\n",
+ ia->timing_advance2,
+ ia->timing_advance2 * GSM_TA_CM / 100,
+ ia->req_ref2.ra, ia->chan_desc2.chan_nr, cd2.maio,
+ cd2.hsn, ch_ts, ch_subch, cd2.tsc);
} else {
cd2.h = 0;
gsm48_decode_chan_h0(&ia->chan_desc2, &cd2.tsc, &cd2.arfcn);
- LOGP(DRR, LOGL_INFO, "2(ra=0x%02x, "
- "chan_nr=0x%02x, ARFCN=%u, TS=%u, SS=%u, TSC=%u)\n",
+ LOGP(DRR, LOGL_INFO, " assignment 2 (ta %d/%dm ra 0x%02x "
+ "chan_nr 0x%02x ARFCN %u TS %u SS %u TSC %u)\n",
+ ia->timing_advance2,
+ ia->timing_advance2 * GSM_TA_CM / 100,
ia->req_ref2.ra, ia->chan_desc2.chan_nr, cd2.arfcn,
ch_ts, ch_subch, cd2.tsc);
}
/* 3.3.1.1.2: ignore assignment while idle */
if (rr->state != GSM48_RR_ST_CONN_PEND || !rr->wait_assign) {
- LOGP(DRR, LOGL_INFO, "no previous request\n");
+ LOGP(DRR, LOGL_INFO, "Not for us, no request.\n");
return 0;
}
rr->wait_assign = 0;
return gsm48_rr_dl_est(ms);
}
- LOGP(DRR, LOGL_INFO, "does not match our request\n");
+ LOGP(DRR, LOGL_INFO, "Request, but not for us.\n");
return 0;
}
* link establishment and release
*/
+/* process "Loss Of Signal" */
+int gsm48_rr_los(struct osmocom_ms *ms)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ uint8_t *mode;
+ struct msgb *nmsg;
+ struct gsm48_rr_hdr *nrrh;
+
+ LOGP(DSUM, LOGL_INFO, "Radio link lost signal\n");
+
+ /* stop T3211 if running */
+ stop_rr_t3110(rr);
+
+ switch(rr->state) {
+ case GSM48_RR_ST_CONN_PEND:
+ LOGP(DRR, LOGL_INFO, "LOS during RACH request\n");
+
+ /* stop pending RACH timer */
+ stop_rr_t3126(rr);
+ break;
+ case GSM48_RR_ST_DEDICATED:
+ LOGP(DRR, LOGL_INFO, "LOS during dedicated mode, release "
+ "locally\n");
+
+ new_rr_state(rr, GSM48_RR_ST_REL_PEND);
+
+ /* release message */
+ rel_local:
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ mode = msgb_put(nmsg, 2);
+ mode[0] = RSL_IE_RELEASE_MODE;
+ mode[1] = 1; /* local release */
+ /* start release */
+ return gsm48_send_rsl(ms, RSL_MT_REL_REQ, nmsg);
+ case GSM48_RR_ST_REL_PEND:
+ LOGP(DRR, LOGL_INFO, "LOS during RR release procedure, release "
+ "locally\n");
+
+ /* stop pending RACH timer */
+ stop_rr_t3110(rr);
+
+ /* release locally */
+ goto rel_local;
+ default:
+ /* this should not happen */
+ LOGP(DRR, LOGL_ERROR, "LOS in IDLE state, ignoring\n");
+ return -EINVAL;
+ }
+
+ /* send inication to upper layer */
+ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
+ if (!nmsg)
+ return -ENOMEM;
+ nrrh = (struct gsm48_rr_hdr *)nmsg->data;
+ nrrh->cause = RR_REL_CAUSE_LOST_SIGNAL;
+ gsm48_rr_upmsg(ms, nmsg);
+
+ /* return idle */
+ new_rr_state(rr, GSM48_RR_ST_IDLE);
+ return 0;
+}
+
/* activate link and send establish request */
static int gsm48_rr_dl_est(struct osmocom_ms *ms)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm_subscriber *subscr = &ms->subscr;
+ struct gsm322_cellsel *cs = &ms->cellsel;
+ struct gsm48_sysinfo *s = cs->si;
struct msgb *nmsg;
struct gsm48_hdr *gh;
struct gsm48_pag_rsp *pr;
uint8_t mi[11];
+ uint8_t ch_type, ch_subch, ch_ts;
+ uint16_t ma[64];
+ uint8_t ma_len;
/* 3.3.1.1.3.1 */
stop_rr_t3126(rr);
- /* flush pending RACH requests */
-#ifdef TODO
- rr->n_chan_req = 0; // just to be safe
- nmsg = msgb_alloc_headroom(20, 16, "RAND_FLUSH");
- if (!nmsg)
- return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_RAND_ACC_FLSH, msg);
-#else
- if (bsc_timer_pending(&rr->temp_rach_ti))
- bsc_del_timer(&rr->temp_rach_ti);
-#endif
+ if (rr->cd_now.h) {
+ gsm48_decode_mobile_alloc(s, rr->cd_now.mob_alloc_lv + 1,
+ rr->cd_now.mob_alloc_lv[0], ma, &ma_len, 0);
+ if (ma_len < 1) {
+ LOGP(DRR, LOGL_NOTICE, "Hopping, but no allocation\n");
+ return -EINVAL;
+ }
+ }
/* send DL_EST_REQ */
if (rr->rr_est_msg) {
#ifdef TODO
RSL_MT_ to activate channel with all the cd_now informations
#else
- rr->arfcn = rr->cd_now.chan_nr;
- tx_ph_dm_est_req(ms, rr->cd_now.arfcn, rr->arfcn);
+ rsl_dec_chan_nr(rr->cd_now.chan_nr, &ch_type, &ch_subch, &ch_ts);
+ if ((ch_type != RSL_CHAN_SDCCH8_ACCH
+ && ch_type != RSL_CHAN_SDCCH4_ACCH) || ch_ts > 4) {
+ printf("Channel type %d, subch %d, ts %d not supported, "
+ "exitting.\n", ch_type, ch_subch, ch_ts);
+ exit(-ENOTSUP);
+ }
+ if (rr->cd_now.h)
+ tx_ph_dm_est_req_h1(ms, rr->cd_now.maio, rr->cd_now.hsn,
+ ma, ma_len, rr->cd_now.chan_nr, rr->cd_now.tsc, 0);
+ else
+ tx_ph_dm_est_req_h0(ms, rr->cd_now.arfcn, rr->cd_now.chan_nr,
+ rr->cd_now.tsc, 0);
#endif
/* start establishmnet */
static int gsm48_rr_estab_cnf(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
+ uint8_t *mode;
struct msgb *nmsg;
/* if MM has releases before confirm, we start release */
- if (rr->state == GSM48_RR_ST_IDLE) {
+ if (rr->state == GSM48_RR_ST_REL_PEND) {
LOGP(DRR, LOGL_INFO, "MM already released RR.\n");
/* release message */
nmsg = gsm48_l3_msgb_alloc();
if (!nmsg)
return -ENOMEM;
+ mode = msgb_put(nmsg, 2);
+ mode[0] = RSL_IE_RELEASE_MODE;
+ mode[1] = 0; /* normal release */
/* start release */
return gsm48_send_rsl(ms, RSL_MT_REL_REQ, nmsg);
}
return gsm48_rr_upmsg(ms, nmsg);
}
-/* the link is released */
-static int gsm48_rr_rel_cnf(struct osmocom_ms *ms, struct msgb *msg)
+/* the link is released in pending state (by l2) */
+static int gsm48_rr_rel_ind(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct msgb *nmsg;
+ struct gsm48_rr_hdr *nrrh;
- /* deactivate channel */
- LOGP(DRR, LOGL_INFO, "deactivating channel (arfcn %d)\n", rr->arfcn);
-#ifdef TODO
- release and give new arfcn
- tx_ph_dm_rel_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
+ LOGP(DSUM, LOGL_INFO, "Radio link is released\n");
+
+ /* send inication to upper layer */
+ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
+ if (!nmsg)
+ return -ENOMEM;
+ nrrh = (struct gsm48_rr_hdr *)nmsg->data;
+ nrrh->cause = RR_REL_CAUSE_NORMAL;
+ gsm48_rr_upmsg(ms, nmsg);
+
+ /* start release timer, so UA will be transmitted */
+ start_rr_t_rel_wait(rr, 1, 500000);
+
+ /* pending release */
+ new_rr_state(rr, GSM48_RR_ST_REL_PEND);
+
+ return 0;
+}
+
+/* 9.1.7 CHANNEL RELEASE is received */
+static int gsm48_rr_rx_chan_rel(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ struct gsm48_chan_rel *cr = (struct gsm48_chan_rel *)gh->data;
+ int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*cr);
+ struct tlv_parsed tp;
+ struct msgb *nmsg;
+ uint8_t *mode;
+
+ if (payload_len < 0) {
+ LOGP(DRR, LOGL_NOTICE, "Short read of CHANNEL RELEASE "
+ "message.\n");
+ return gsm48_rr_tx_rr_status(ms,
+ GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
+ }
+ tlv_parse(&tp, &gsm48_rr_att_tlvdef, cr->data, payload_len, 0, 0);
+
+ LOGP(DRR, LOGL_INFO, "channel release request with cause 0x%02x)\n",
+ cr->rr_cause);
+
+ /* BA range */
+ if (TLVP_PRESENT(&tp, GSM48_IE_BA_RANGE)) {
+ gsm48_decode_ba_range(TLVP_VAL(&tp, GSM48_IE_BA_RANGE),
+ *(TLVP_VAL(&tp, GSM48_IE_BA_RANGE) - 1), rr->ba_range,
+ &rr->ba_ranges,
+ sizeof(rr->ba_range) / sizeof(rr->ba_range[0]));
+ /* NOTE: the ranges are kept until IDLE state is returned
+ * (see new_rr_state)
+ */
+ }
+
+ new_rr_state(rr, GSM48_RR_ST_REL_PEND);
+
+ /* start T3110, so that two DISCs can be sent due to T200 timeout */
+ start_rr_t3110(rr, 1, 500000);
+
+ /* disconnect the main signalling link */
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ mode = msgb_put(nmsg, 2);
+ mode[0] = RSL_IE_RELEASE_MODE;
+ mode[1] = 0; /* normal release */
+ return gsm48_send_rsl(ms, RSL_MT_REL_REQ, nmsg);
+}
+
+/*
+ * assignment and handover
+ */
+
+/* 9.1.3 sending ASSIGNMENT COMPLETE */
+static int gsm48_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause)
+{
+ struct msgb *nmsg;
+ struct gsm48_hdr *gh;
+ struct gsm48_ass_cpl *ac;
+
+ LOGP(DRR, LOGL_INFO, "ASSIGNMENT COMPLETE (cause #%d)\n", cause);
+
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
+ ac = (struct gsm48_ass_cpl *) msgb_put(nmsg, sizeof(*ac));
+
+ gh->proto_discr = GSM48_PDISC_RR;
+ gh->msg_type = GSM48_MT_RR_ASS_COMPL;
+
+ /* RR_CAUSE */
+ ac->rr_cause = cause;
+
+ return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+}
+
+/* 9.1.4 sending ASSIGNMENT FAILURE */
+static int gsm48_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause)
+{
+ struct msgb *nmsg;
+ struct gsm48_hdr *gh;
+ struct gsm48_ass_fail *af;
+
+ LOGP(DRR, LOGL_INFO, "ASSIGNMENT FAILURE (cause #%d)\n", cause);
+
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
+ af = (struct gsm48_ass_fail *) msgb_put(nmsg, sizeof(*af));
+
+ gh->proto_discr = GSM48_PDISC_RR;
+ gh->msg_type = GSM48_MT_RR_ASS_COMPL;
+
+ /* RR_CAUSE */
+ af->rr_cause = cause;
+
+ return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+}
+
+/* 9.1.2 ASSIGNMENT COMMAND is received */
+static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
+{
+// struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ struct gsm48_ass_cmd *ac = (struct gsm48_ass_cmd *)gh->data;
+ int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*ac);
+ struct tlv_parsed tp;
+ struct gsm48_rr_cd cd;
+
+ LOGP(DRR, LOGL_INFO, "ASSIGNMENT COMMAND\n");
+
+ memset(&cd, 0, sizeof(cd));
+
+ if (payload_len < 0) {
+ LOGP(DRR, LOGL_NOTICE, "Short read of ASSIGNMENT COMMAND message.\n");
+ return gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
+ }
+ tlv_parse(&tp, &gsm48_rr_att_tlvdef, ac->data, payload_len, 0, 0);
+
+#if 0
+ /* channel description */
+ memcpy(&cd.chan_desc, &ac->chan_desc, sizeof(chan_desc));
+ /* power command */
+ cd.power_command = ac->power_command;
+ /* frequency list, after timer */
+ tlv_copy(&cd.fl, sizeof(fl_after), &tp, GSM48_IE_FRQLIST_AFTER);
+ /* cell channel description */
+ tlv_copy(&cd.ccd, sizeof(ccd), &tp, GSM48_IE_CELL_CH_DESC);
+ /* multislot allocation */
+ tlv_copy(&cd.multia, sizeof(ma), &tp, GSM48_IE_MSLOT_DESC);
+ /* channel mode */
+ tlv_copy(&cd.chanmode, sizeof(chanmode), &tp, GSM48_IE_CHANMODE_1);
+ /* mobile allocation, after time */
+ tlv_copy(&cd.moba_after, sizeof(moba_after), &tp, GSM48_IE_MOB_AL_AFTER);
+ /* starting time */
+ tlv_copy(&cd.start, sizeof(start), &tp, GSM_IE_START_TIME);
+ /* frequency list, before time */
+ tlv_copy(&cd.fl_before, sizeof(fl_before), &tp, GSM48_IE_FRQLIST_BEFORE);
+ /* channel description, before time */
+ tlv_copy(&cd.chan_desc_before, sizeof(cd_before), &tp, GSM48_IE_CHDES_1_BEFORE);
+ /* frequency channel sequence, before time */
+ tlv_copy(&cd.fcs_before, sizeof(fcs_before), &tp, GSM48_IE_FRQSEQ_BEFORE);
+ /* mobile allocation, before time */
+ tlv_copy(&cd.moba_before, sizeof(moba_before), &tp, GSM48_IE_MOB_AL_BEFORE);
+ /* cipher mode setting */
+ if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET))
+ cd.cipher = *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET);
+ else
+ cd.cipher = 0;
+
+ if (no CA) {
+ LOGP(DRR, LOGL_INFO, "No current cell allocation available.\n");
+ return gsm48_rr_tx_ass_fail(ms, GSM48_GSM48_RR_CAUSE_NO_CELL_ALLOC_A);
+ }
+
+ if (not supported) {
+ LOGP(DRR, LOGL_INFO, "New channel is not supported.\n");
+ return gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_CHAN_MODE_UNACCEPT);
+ }
+
+ if (freq not supported) {
+ LOGP(DRR, LOGL_INFO, "New frequency is not supported.\n");
+ return gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_FREQ_NOT_IMPL);
+ }
+
+ /* store current channel descriptions, to return in case of failure */
+ memcpy(&rr->chan_last, &rr->chan_desc, sizeof(*cd));
+ /* copy new description */
+ memcpy(&rr->chan_desc, cd, sizeof(cd));
+
+ /* start suspension of current link */
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, msg);
+
+ /* change into special assignment suspension state */
+ rr->assign_susp_state = 1;
+ rr->resume_last_state = 0;
#else
- l1ctl_tx_ccch_req(ms, rr->arfcn);
+ return gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_FREQ_NOT_IMPL);
#endif
- /* 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;
}
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct gsm48_sysinfo *s = cs->si;
struct gsm_subscriber *subscr = &ms->subscr;
struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data;
struct gsm48_hdr *gh = msgb_l3(msg);
LOGP(DRR, LOGL_INFO, "T3122 running, rejecting!\n");
cause = RR_REL_CAUSE_T3122;
reject:
+ LOGP(DSUM, LOGL_INFO, "Establishing radio link not "
+ "possible\n");
nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
if (!nmsg)
return -ENOMEM;
stop_rr_t3122(rr);
}
- /* check if camping */
- if (cs->state != GSM322_C3_CAMPED_NORMALLY
- && rrh->cause != RR_EST_CAUSE_EMERGENCY) {
- LOGP(DRR, LOGL_INFO, "Not camping normally, rejecting!\n");
- cause = RR_REL_CAUSE_EMERGENCY_ONLY;
+ /* if state is not idle */
+ if (rr->state != GSM48_RR_ST_IDLE) {
+ LOGP(DRR, LOGL_INFO, "We are not IDLE yet, rejecting!\n");
+ cause = RR_REL_CAUSE_TRY_LATER;
+ goto reject;
+ }
+
+ /* cell selected */
+ if (!cs->selected) {
+ LOGP(DRR, LOGL_INFO, "No cell selected, rejecting!\n");
+ cause = RR_REL_CAUSE_TRY_LATER;
+ goto reject;
+ }
+
+ /* check if camping */
+ if (cs->state != GSM322_C3_CAMPED_NORMALLY
+ && rrh->cause != RR_EST_CAUSE_EMERGENCY) {
+ LOGP(DRR, LOGL_INFO, "Not camping normally, rejecting!\n");
+ cause = RR_REL_CAUSE_EMERGENCY_ONLY;
goto reject;
}
if (cs->state != GSM322_C3_CAMPED_NORMALLY
LOGP(DRR, LOGL_ERROR, "Error, missing l3 message\n");
return -EINVAL;
}
- rr->rr_est_msg = msgb_alloc_headroom(256, 16, "EST_REQ");
+ rr->rr_est_msg = gsm48_l3_msgb_alloc();
if (!rr->rr_est_msg)
return -ENOMEM;
memcpy(msgb_put(rr->rr_est_msg, msgb_l3len(msg)),
msgb_l3(msg), msgb_l3len(msg));
/* request channel */
- return gsm48_rr_tx_chan_req(ms, rrh->cause, 0);
+ return gsm48_rr_chan_req(ms, rrh->cause, 0);
}
/* send all queued messages down to layer 2 */
case GSM48_MT_RR_ADD_ASS:
rc = gsm48_rr_rx_add_ass(ms, msg);
break;
-#if 0
case GSM48_MT_RR_ASS_CMD:
rc = gsm48_rr_rx_ass_cmd(ms, msg);
break;
+#if 0
case GSM48_MT_RR_CIP_MODE_CMD:
rc = gsm48_rr_rx_cip_mode_cmd(ms, msg);
break;
rc = gsm48_rr_rx_freq_redef(ms, msg);
break;
#endif
+ case GSM48_MT_RR_CHAN_REL:
+ rc = gsm48_rr_rx_chan_rel(ms, msg);
+ break;
default:
LOGP(DRR, LOGL_NOTICE, "Message type 0x%02x unknown.\n",
gh->msg_type);
case GSM48_MT_RR_SYSINFO_4:
return gsm48_rr_rx_sysinfo4(ms, msg);
default:
- LOGP(DRR, LOGL_NOTICE, "BCCH message type 0x%02x unknown.\n",
+#if 0
+ LOGP(DRR, LOGL_NOTICE, "BCCH message type 0x%02x not sup.\n",
sih->system_information);
+#endif
return -EINVAL;
}
}
/* receive CCCH at RR layer */
-static int gsm48_rr_rx_ccch(struct osmocom_ms *ms, struct msgb *msg)
+static int gsm48_rr_rx_pch_agch(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_system_information_type_header *sih = msgb_l3(msg);
- struct gsm322_cellsel *cs = &ms->cellsel;
-
- /* when changing/deactivating ccch, ignore pending messages */
- if (!cs->ccch_active)
- return -EINVAL;
switch (sih->system_information) {
- case GSM48_MT_RR_SYSINFO_5:
- return gsm48_rr_rx_sysinfo5(ms, msg);
- case GSM48_MT_RR_SYSINFO_5bis:
- return gsm48_rr_rx_sysinfo5bis(ms, msg);
- case GSM48_MT_RR_SYSINFO_5ter:
- return gsm48_rr_rx_sysinfo5ter(ms, msg);
- case GSM48_MT_RR_SYSINFO_6:
- return gsm48_rr_rx_sysinfo6(ms, msg);
-
case GSM48_MT_RR_PAG_REQ_1:
return gsm48_rr_rx_pag_req_1(ms, msg);
case GSM48_MT_RR_PAG_REQ_2:
return gsm48_rr_rx_pag_req_2(ms, msg);
case GSM48_MT_RR_PAG_REQ_3:
return gsm48_rr_rx_pag_req_3(ms, msg);
+
case GSM48_MT_RR_IMM_ASS:
return gsm48_rr_rx_imm_ass(ms, msg);
case GSM48_MT_RR_IMM_ASS_EXT:
}
}
+/* receive ACCH at RR layer */
+static int gsm48_rr_rx_acch(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_system_information_type_header *sih = msgb_l3(msg);
+
+ switch (sih->system_information) {
+ case GSM48_MT_RR_SYSINFO_5:
+ return gsm48_rr_rx_sysinfo5(ms, msg);
+ case GSM48_MT_RR_SYSINFO_5bis:
+ return gsm48_rr_rx_sysinfo5bis(ms, msg);
+ case GSM48_MT_RR_SYSINFO_5ter:
+ return gsm48_rr_rx_sysinfo5ter(ms, msg);
+ case GSM48_MT_RR_SYSINFO_6:
+ return gsm48_rr_rx_sysinfo6(ms, msg);
+ default:
+ LOGP(DRR, LOGL_NOTICE, "ACCH message type 0x%02x unknown.\n",
+ sih->system_information);
+ return -EINVAL;
+ }
+}
+
/* unit data from layer 2 to RR layer */
static int gsm48_rr_unit_data_ind(struct osmocom_ms *ms, struct msgb *msg)
{
+ struct gsm322_cellsel *cs = &ms->cellsel;
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
struct tlv_parsed tv;
}
msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO);
- switch (rllh->chan_nr) {
- case RSL_CHAN_PCH_AGCH:
- return gsm48_rr_rx_ccch(ms, msg);
- case RSL_CHAN_BCCH:
+ if (cs->ccch_state != GSM322_CCCH_ST_SYNC
+ && cs->ccch_state != GSM322_CCCH_ST_DATA)
+ return -EINVAL;
+
+ /* when camping, start/reset loss timer */
+ if (cs->state == GSM322_C3_CAMPED_NORMALLY
+ || cs->state == GSM322_C7_CAMPED_ANY_CELL) {
+ struct gsm48_sysinfo *s = &ms->cellsel.sel_si;
+#ifdef TODO
+ set radio link timeout on layer 1
+ it is the number of subsequent BCCH blocks. (about 1/4 seconds)
+#else
+ start_loss_timer(cs, s->bcch_radio_link_timeout / 4, 0);
+#endif
+ }
+
+ /* temporary moved here until confirm is fixed */
+ if (cs->ccch_state != GSM322_CCCH_ST_DATA) {
+ LOGP(DCS, LOGL_INFO, "Channel provides data.\n");
+ cs->ccch_state = GSM322_CCCH_ST_DATA;
+
+ /* in dedicated mode */
+ if (ms->rrlayer.state == GSM48_RR_ST_CONN_PEND)
+ return gsm48_rr_tx_rand_acc(ms, NULL);
+
+ /* set timer for reading BCCH */
+ if (cs->state == GSM322_C2_STORED_CELL_SEL
+ || cs->state == GSM322_C1_NORMAL_CELL_SEL
+ || cs->state == GSM322_C6_ANY_CELL_SEL
+ || cs->state == GSM322_C4_NORMAL_CELL_RESEL
+ || cs->state == GSM322_C8_ANY_CELL_RESEL
+ || cs->state == GSM322_C5_CHOOSE_CELL
+ || cs->state == GSM322_C9_CHOOSE_ANY_CELL
+ || cs->state == GSM322_PLMN_SEARCH
+ || cs->state == GSM322_HPLMN_SEARCH)
+ start_cs_timer(cs, ms->support.scan_to, 0);
+ // TODO: timer depends on BCCH config
+ }
+
+ if (rllh->chan_nr == RSL_CHAN_PCH_AGCH)
+ return gsm48_rr_rx_pch_agch(ms, msg);
+ if (rllh->chan_nr == RSL_CHAN_BCCH)
return gsm48_rr_rx_bcch(ms, msg);
- default:
- LOGP(DRSL, LOGL_NOTICE, "RSL with chan_nr 0x%02x unknown.\n",
- rllh->chan_nr);
- return -EINVAL;
+ if ((rllh->chan_nr & 0xf0) == RSL_CHAN_SDCCH4_ACCH)
+ return gsm48_rr_rx_acch(ms, msg);
+ if ((rllh->chan_nr & 0xf0) == RSL_CHAN_SDCCH8_ACCH)
+ return gsm48_rr_rx_acch(ms, msg);
+ LOGP(DRSL, LOGL_NOTICE, "RSL with chan_nr 0x%02x unknown.\n",
+ rllh->chan_nr);
+ return -EINVAL;
+}
+
+/* 3.4.13.3 RR abort in dedicated mode (also in conn. pending mode) */
+static int gsm48_rr_abort_req(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ uint8_t *mode;
+
+ /* stop pending RACH timer */
+ stop_rr_t3126(rr);
+
+ /* release "normally" if we are in dedicated mode */
+ if (rr->state == GSM48_RR_ST_DEDICATED) {
+ struct msgb *nmsg;
+
+ LOGP(DRR, LOGL_INFO, "Abort in dedicated state, send release "
+ "to layer 2.\n");
+
+ new_rr_state(rr, GSM48_RR_ST_REL_PEND);
+
+ /* release message */
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ mode = msgb_put(nmsg, 2);
+ mode[0] = RSL_IE_RELEASE_MODE;
+ mode[1] = 0; /* normal release */
+ return gsm48_send_rsl(ms, RSL_MT_REL_REQ, nmsg);
}
+
+ LOGP(DRR, LOGL_INFO, "Abort in connection pending state, return to "
+ "idle state.\n");
+ /* return idle */
+ new_rr_state(rr, GSM48_RR_ST_REL_PEND);
+
+ return 0;
+}
+
+/* release confirm in dedicated mode */
+static int gsm48_rr_susp_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+
+ if (rr->hando_susp_state || rr->assign_susp_state) {
+ struct msgb *nmsg;
+
+ /* change radio to new channel */
+//todo tx_ph_dm_est_req(ms, rr->cd_now.arfcn, rr->cd_now.chan_nr,
+// rr->cd_now.tsc);
+
+ /* send DL-ESTABLISH REQUEST */
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
+
+#ifdef TODO
+ /* trigger RACH */
+ if (rr->hando_susp_state) {
+ gsm48_rr_tx_hando_access(ms);
+ rr->hando_acc_left = 3;
+ }
+#endif
+ }
+ return 0;
+}
+
+/* release confirm */
+static int gsm48_rr_rel_cnf(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct msgb *nmsg;
+ struct gsm48_rr_hdr *nrrh;
+
+ LOGP(DSUM, LOGL_INFO, "Requesting channel aborted\n");
+
+ /* stop T3211 if running */
+ stop_rr_t3110(rr);
+
+ /* send release indication */
+ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
+ if (!nmsg)
+ return -ENOMEM;
+ nrrh = (struct gsm48_rr_hdr *)nmsg->data;
+ nrrh->cause = RR_REL_CAUSE_NORMAL;
+ gsm48_rr_upmsg(ms, nmsg);
+
+ /* return idle */
+ new_rr_state(rr, GSM48_RR_ST_IDLE);
+ return 0;
}
/*
static struct dldatastate {
uint32_t states;
int type;
- const char *type_name;
int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
} dldatastatelist[] = {
- {SBIT(GSM48_RR_ST_IDLE) | SBIT(GSM48_RR_ST_CONN_PEND),
- RSL_MT_UNIT_DATA_IND, "UNIT_DATA_IND", gsm48_rr_unit_data_ind},
+ /* data transfer */
+ {SBIT(GSM48_RR_ST_IDLE) |
+ SBIT(GSM48_RR_ST_CONN_PEND) |
+ SBIT(GSM48_RR_ST_DEDICATED) |
+ SBIT(GSM48_RR_ST_REL_PEND),
+ RSL_MT_UNIT_DATA_IND, gsm48_rr_unit_data_ind},
+
{SBIT(GSM48_RR_ST_DEDICATED), /* 3.4.2 */
- RSL_MT_DATA_IND, "DATA_IND", gsm48_rr_data_ind},
- {SBIT(GSM48_RR_ST_IDLE) | SBIT(GSM48_RR_ST_CONN_PEND),
- RSL_MT_EST_CONF, "EST_CONF", gsm48_rr_estab_cnf},
+ RSL_MT_DATA_IND, gsm48_rr_data_ind},
+
+ /* esablish */
+ {SBIT(GSM48_RR_ST_CONN_PEND), /* 3.3.1.1.2 */
+ RSL_MT_CHAN_CNF, gsm48_rr_tx_rand_acc},
+
+ {SBIT(GSM48_RR_ST_IDLE) |
+ SBIT(GSM48_RR_ST_CONN_PEND) |
+ SBIT(GSM48_RR_ST_REL_PEND),
+ RSL_MT_EST_CONF, gsm48_rr_estab_cnf},
+
#if 0
{SBIT(GSM48_RR_ST_DEDICATED),
- RSL_MT_EST_CONF, "EST_CONF", gsm48_rr_estab_cnf_dedicated},
- {SBIT(GSM_RRSTATE),
- RSL_MT_CONNECT_CNF, "CONNECT_CNF", gsm48_rr_connect_cnf},
+ RSL_MT_EST_CONF, gsm48_rr_estab_cnf_dedicated},
+
{SBIT(GSM_RRSTATE),
- RSL_MT_RELEASE_IND, "REL_IND", gsm48_rr_rel_ind},
+ RSL_MT_CONNECT_CNF, gsm48_rr_connect_cnf},
+
#endif
- {SBIT(GSM48_RR_ST_IDLE) | SBIT(GSM48_RR_ST_CONN_PEND),
- RSL_MT_REL_CONF, "REL_CONF", gsm48_rr_rel_cnf},
-#if 0
+
+ /* release */
+ {SBIT(GSM48_RR_ST_CONN_PEND) |
+ SBIT(GSM48_RR_ST_DEDICATED),
+ RSL_MT_REL_IND, gsm48_rr_rel_ind},
+
+ {SBIT(GSM48_RR_ST_REL_PEND),
+ RSL_MT_REL_CONF, gsm48_rr_rel_cnf},
+
+ /* suspenion */
{SBIT(GSM48_RR_ST_DEDICATED),
- RSL_MT_REL_CONF, "REL_CONF", gsm48_rr_rel_cnf_dedicated},
-#endif
- {SBIT(GSM48_RR_ST_CONN_PEND), /* 3.3.1.1.2 */
- RSL_MT_CHAN_CNF, "CHAN_CNF", gsm48_rr_rand_acc_cnf},
+ RSL_MT_SUSP_CONF, gsm48_rr_susp_cnf_dedicated},
+
#if 0
{SBIT(GSM48_RR_ST_DEDICATED),
- RSL_MT_CHAN_CNF, "CHAN_CNF", gsm48_rr_rand_acc_cnf_dedicated},
+ RSL_MT_CHAN_CNF, gsm48_rr_rand_acc_cnf_dedicated},
+
{SBIT(GSM_RRSTATE),
- RSL_MT_MDL_ERROR_IND, "MDL_ERROR_IND", gsm48_rr_mdl_error_ind},
+ RSL_MT_MDL_ERROR_IND, gsm48_rr_mdl_error_ind},
#endif
};
int i;
int rc;
+ if (msg_type != RSL_MT_UNIT_DATA_IND) {
+ LOGP(DRSL, LOGL_INFO, "(ms %s) Received '%s' from L2 in state "
+ "%s\n", ms->name, get_rsl_name(msg_type),
+ gsm48_rr_state_names[rr->state]);
+ }
+
/* find function for current state and message */
for (i = 0; i < DLDATASLLEN; i++)
if ((msg_type == dldatastatelist[i].type)
&& ((1 << rr->state) & dldatastatelist[i].states))
break;
if (i == DLDATASLLEN) {
- LOGP(DRSL, LOGL_NOTICE, "RSLms message 0x%02x unhandled at "
- "state %s.\n", msg_type, gsm48_rr_state_names[rr->state]);
+ LOGP(DRSL, LOGL_NOTICE, "RSLms message unhandled\n");
msgb_free(msg);
return 0;
}
- LOGP(DRSL, LOGL_INFO, "(ms %s) Received 'RSL_MT_%s' from RSL in state "
- "%s\n", ms->name, dldatastatelist[i].type_name,
- gsm48_rr_state_names[rr->state]);
rc = dldatastatelist[i].rout(ms, msg);
/* free msgb unless it is forwarded */
if (dldatastatelist[i].rout != gsm48_rr_data_ind)
-#warning HACK!!!!!!
-return rc;
msgb_free(msg);
return rc;
int type;
int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
} rrdownstatelist[] = {
- {SBIT(GSM48_RR_ST_IDLE), /* 3.3.1.1 */
+ /* NOTE: If not IDLE, it is rejected there. */
+ {ALL_STATES, /* 3.3.1.1 */
GSM48_RR_EST_REQ, gsm48_rr_est_req},
+
{SBIT(GSM48_RR_ST_DEDICATED), /* 3.4.2 */
GSM48_RR_DATA_REQ, gsm48_rr_data_req},
-#if 0
- {SBIT(GSM48_RR_ST_CONN_PEND) | SBIT(GSM48_RR_ST_DEDICATED),
+
+ {SBIT(GSM48_RR_ST_CONN_PEND) |
+ SBIT(GSM48_RR_ST_DEDICATED), /* 3.4.13.3 */
GSM48_RR_ABORT_REQ, gsm48_rr_abort_req},
+
+#if 0
{SBIT(GSM48_RR_ST_DEDICATED),
GSM48_RR_ACT_REQ, gsm48_rr_act_req},
#endif
rr->rr_est_msg = NULL;
}
+ stop_rr_t_rel_wait(rr);
+ stop_rr_t3110(rr);
stop_rr_t3122(rr);
stop_rr_t3126(rr);
todo:
-add support structure
-initialize support structure
-
-queue messages (rslms_data_req) if channel changes
-
-flush rach msg in all cases: during sending, after its done, and when aborted
stop timers on abort
-debugging. (wenn dies todo erledigt ist, bitte in den anderen code moven)
wird beim abbruch immer der gepufferte cm-service-request entfernt, auch beim verschicken?:
measurement reports
todo rr_sync_ind when receiving ciph, re ass, channel mode modify
todo change procedures, release procedure
-during procedures, like "channel assignment" or "handover", rr requests must be queued
-they must be dequeued when complete
-they queue must be flushed when rr fails
-
-#include <osmocore/protocol/gsm_04_08.h>
-#include <osmocore/msgb.h>
-#include <osmocore/utils.h>
-#include <osmocore/gsm48.h>
-
-static int gsm48_rr_abort_req(struct osmocom_ms *ms, struct gsm48_rr *rrmsg)
-{
- struct gsm48_rrlayer *rr = ms->rrlayer;
- stop_rr_t3126(rr);
- if (rr->state == GSM48_RR_ST_DEDICATED) {
- struct gsm_dl dlmsg;
-
- memset(&dlmsg, 0, sizeof(dlmsg));
- return gsm48_send_rsl(ms, RSL_MT_REL_REQ, nmsg);
- }
- new_rr_state(rr, GSM48_RR_ST_IDLE);
-}
-
static int gsm48_rr_act_req(struct osmocom_ms *ms, struct gsm48_rr *rrmsg)
{
}
return 0;
}
-static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_rrlayer *rr = ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_ass_cmd *ac = (struct gsm48_ass_cmd *)gh->data;
- int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*ac);
- struct tlv_parsed tp;
- struct gsm48_rr_chan_desc cd;
- struct msgb *nmsg;
-
- memset(&cd, 0, sizeof(cd));
-
- if (payload_len < 0) {
- LOGP(DRR, LOGL_NOTICE, "Short read of ASSIGNMENT COMMAND message.\n");
- return gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
- }
- tlv_parse(&tp, &gsm48_rr_att_tlvdef, ac->data, payload_len, 0, 0);
-
- /* channel description */
- memcpy(&cd.chan_desc, &ac->chan_desc, sizeof(chan_desc));
- /* power command */
- cd.power_command = ac->power_command;
- /* frequency list, after timer */
- tlv_copy(&cd.fl, sizeof(fl_after), &tp, GSM48_IE_FRQLIST_AFTER);
- /* cell channel description */
- tlv_copy(&cd.ccd, sizeof(ccd), &tp, GSM48_IE_CELL_CH_DESC);
- /* multislot allocation */
- tlv_copy(&cd.multia, sizeof(ma), &tp, GSM48_IE_MSLOT_DESC);
- /* channel mode */
- tlv_copy(&cd.chanmode, sizeof(chanmode), &tp, GSM48_IE_CHANMODE_1);
- /* mobile allocation, after time */
- tlv_copy(&cd.moba_after, sizeof(moba_after), &tp, GSM48_IE_MOB_AL_AFTER);
- /* starting time */
- tlv_copy(&cd.start, sizeof(start), &tp, GSM_IE_START_TIME);
- /* frequency list, before time */
- tlv_copy(&cd.fl_before, sizeof(fl_before), &tp, GSM48_IE_FRQLIST_BEFORE);
- /* channel description, before time */
- tlv_copy(&cd.chan_desc_before, sizeof(cd_before), &tp, GSM48_IE_CHDES_1_BEFORE);
- /* frequency channel sequence, before time */
- tlv_copy(&cd.fcs_before, sizeof(fcs_before), &tp, GSM48_IE_FRQSEQ_BEFORE);
- /* mobile allocation, before time */
- tlv_copy(&cd.moba_before, sizeof(moba_before), &tp, GSM48_IE_MOB_AL_BEFORE);
- /* cipher mode setting */
- if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET))
- cd.cipher = *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET);
- else
- cd.cipher = 0;
-
- if (no CA) {
- LOGP(DRR, LOGL_INFO, "No current cell allocation available.\n");
- return gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_NO_CELL_ALLOC_A);
- }
-
- if (not supported) {
- LOGP(DRR, LOGL_INFO, "New channel is not supported.\n");
- return gsm48_rr_tx_rr_status(ms, RR_CAUSE_CHAN_MODE_UNACCEPT);
- }
-
- if (freq not supported) {
- LOGP(DRR, LOGL_INFO, "New frequency is not supported.\n");
- return gsm48_rr_tx_rr_status(ms, RR_CAUSE_FREQ_NOT_IMPLEMENTED);
- }
-
- /* store current channel descriptions, to return in case of failure */
- memcpy(&rr->chan_last, &rr->chan_desc, sizeof(*cd));
- /* copy new description */
- memcpy(&rr->chan_desc, cd, sizeof(cd));
-
- /* start suspension of current link */
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, msg);
-
- /* change into special assignment suspension state */
- rr->assign_susp_state = 1;
- rr->resume_last_state = 0;
-
- return 0;
-}
-
-/* decode "BA Range" (10.5.2.1a) */
-static int gsm48_decode_ba_range(uint8_t *ba, uint8_t, ba_len, uint32_t *range,
- uint8_t *ranges, int max_ranges)
-{
- /* ba = pointer to IE without IE type and length octets
- * ba_len = number of octets
- * range = pointer to store decoded range
- * ranges = number of ranges decoded
- * max_ranges = maximum number of decoded ranges that can be stored
- */
- uint16_t lower, higher;
- int i, n, required_octets;
-
- /* find out how much ba ranges will be decoded */
- n = *ba++;
- ba_len --;
- required_octets = 5 * (n >> 1) + 3 * (n & 1);
- if (required_octets > n) {
- *ranges = 0;
- return -EINVAL;
- }
- if (max_ranges > n)
- n = max_ranges;
-
- /* decode ranges */
- for (i = 0; i < n; i++) {
- if (!(i & 1)) {
- /* decode even range number */
- lower = *ba++ << 2;
- lower |= (*ba >> 6);
- higher = (*ba++ & 0x3f) << 4;
- higher |= *ba >> 4;
- } else {
- lower = (*ba++ & 0x0f) << 6;
- lower |= *ba >> 2;
- higher = (*ba++ & 0x03) << 8;
- higher |= *ba++;
- /* decode odd range number */
- }
- *range++ = (higher << 16) | lower;
- }
- *ranges = n;
-
- return 0;
-}
-
/* decode "Cell Description" (10.5.2.2) */
static int gsm48_decode_cell_desc(struct gsm48_cell_desc *cd, uint16_t *arfcn, uint8_t *ncc uint8_t *bcc)
struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *)gh->data;
int payload_len = msgb_l3len(msg) - sizeof(*gh) - wirklich sizeof(*ho);
struct tlv_parsed tp;
- struct gsm48_rr_chan_desc cd;
+ struct gsm48_rr_cd cd;
struct msgb *nmsg;
memset(&cd, 0, sizeof(cd));
/* Synchronization Indication */
if (TLVP_PRESENT(&tp, GSM48_IE_SYNC_IND))
gsm48_decode_sync_ind(rr,
- TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC)-1, &cd);
+ TLVP_VAL(&tp, GSM48_IE_SYNC_IND)-1, &cd);
/* Frequency Sort List */
if (TLVP_PRESENT(&tp, GSM48_IE_FREQ_SHORT_LIST))
gsm48_decode_freq_list(&ms->support, s->freq,
- TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC),
- *(TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC)-1),
+ TLVP_VAL(&tp, GSM48_IE_FREQ_SHORT_LIST),
+ *(TLVP_VAL(&tp, GSM48_IE_FREQ_SHORT_LIST)-1),
0xce, FREQ_TYPE_SERV);
rr->resume_last_state = 0;
gsm48_rr_tx_ass_cpl(ms, GSM48_RR_CAUSE_NORMAL);
} else {
- gsm48_rr_tx_ass_fail(ms, RR_CAUSE_PROTO_ERR_UNSPEC);
+ gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_PROTO_ERR_UNSPEC);
}
/* transmit queued frames during ho / ass transition */
gsm48_rr_dequeue_down(ms);
{
}
-static int gsm48_rr_rel_ind(struct osmocom_ms *ms, struct msgb *msg)
-{
-}
-
-static int gsm48_rr_rel_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
+static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_rrlayer *rr = ms->rrlayer;
struct msgb *nmsg;
+ struct gsm_rr_hdr *nrrh;
- if (rr->hando_susp_state || rr->assign_susp_state) {
- struct msgb *msg;
-
- /* change radio to new channel */
- rr->arfcn = rr->chan_desc.chan_desc.chan_nr;
- tx_ph_dm_est_req(ms, arfcn, rr->arfcn);
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- /* send DL-ESTABLISH REQUEST */
- gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
+ printing of the cause
+ switch (msg->l3h[0]) {
+ case RLL_CAUSE_SEQ_ERR:
+ case RLL_CAUSE_UNSOL_DM_RESP_MF:
+ einige muessen ignoriert werden
+ andere gelten als release
}
- if (rr->hando_susp_state) {
- gsm48_rr_tx_hando_access(ms);
- rr->hando_acc_left = 3;
- }
- return 0;
-}
-
-static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_rrlayer *rr = ms->rrlayer;
- struct msgb *nmsg;
- struct gsm_rr_hdr *nrrh;
if (rr->hando_susp_state || rr->assign_susp_state) {
if (!rr->resume_last_state) {
memcpy(&rr->chan_desc, &rr->chan_last, sizeof(*cd));
/* change radio to old channel */
- rr->arfcn = rr->chan_desc.chan_desc.chan_nr;
- tx_ph_dm_est_req(ms, arfcn, rr->arfcn);
+ tx_ph_dm_est_req(ms, rr->cd_now.arfcn,
+ rr->cd_now.chan_nr, rr->cd_now.tsc);
/* re-establish old link */
nmsg = gsm48_l3_msgb_alloc();
if (!nmsg)
return -ENOMEM;
- return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_RECON_REQ, nmsg);
}
rr->resume_last_state = 0;
}
memcpy(&rr->chan_desc, &rr->chan_last, sizeof(*cd));
/* change radio to old channel */
- rr->arfcn = rr->chan_desc.chan_desc.chan_nr;
- tx_ph_dm_est_req(ms, arfcn, rr->arfcn);
+ tx_ph_dm_est_req(ms, rr->cd_now.arfcn, rr->cd_now.chan_nr,
+ rr->cd_now.tsc);
/* re-establish old link */
nmsg = gsm48_l3_msgb_alloc();
if (!nmsg)
return -ENOMEM;
- return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
+ return gsm48_send_rsl(ms, RSL_MT_REEST_REQ, nmsg);
todo
}