modem: request an Uplink TBF, match Immediate Assignment

Change-Id: Iec0dcc629d29dec270649cf7428f71af0dfd2dbb
Related: SYS#5500
This commit is contained in:
Vadim Yanitskiy 2023-01-12 17:25:21 +06:00
parent e9abf7b61d
commit 49d993e4ab
1 changed files with 95 additions and 1 deletions

View File

@ -45,8 +45,28 @@
static struct {
enum ccch_mode ccch_mode;
struct gsm48_sysinfo si;
/* TODO: use mobile->rrlayer API instead */
struct {
bool ref_valid;
struct gsm48_req_ref ref;
} chan_req;
} app_data;
/* Generate a 8-bit CHANNEL REQUEST message as per 3GPP TS 44.018, 9.1.8 */
static uint8_t gen_chan_req(bool single_block)
{
uint8_t rnd = (uint8_t)rand();
if (single_block) /* 01110xxx */
return 0x70 | (rnd & 0x07);
/* 011110xx or 01111x0x or 01111xx0 */
if ((rnd & 0x07) == 0x07)
return 0x78;
return 0x78 | (rnd & 0x07);
}
static int handle_si1(struct osmocom_ms *ms, struct msgb *msg)
{
int rc;
@ -127,6 +147,7 @@ static int handle_si4(struct osmocom_ms *ms, struct msgb *msg)
static int handle_si13(struct osmocom_ms *ms, struct msgb *msg)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
int rc;
if (msgb_l3len(msg) != GSM_MACBLOCK_LEN)
@ -138,6 +159,20 @@ static int handle_si13(struct osmocom_ms *ms, struct msgb *msg)
if (rc != 0)
return rc;
/* HACK: request an Uplink TBF here (one phase access) */
if (rr->state == GSM48_RR_ST_IDLE) {
if (!app_data.si.si1)
return 0;
if (!app_data.si.gprs.supported)
return 0;
rr->cr_ra = gen_chan_req(false);
LOGP(DRR, LOGL_NOTICE, "Sending CHANNEL REQUEST (0x%02x)\n", rr->cr_ra);
l1ctl_tx_rach_req(ms, RSL_CHAN_RACH, 0x00, rr->cr_ra, 0,
app_data.ccch_mode == CCCH_MODE_COMBINED);
rr->state = GSM48_RR_ST_CONN_PEND;
}
return 0;
}
@ -166,6 +201,7 @@ static int modem_rx_bcch(struct osmocom_ms *ms, struct msgb *msg)
static int modem_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
{
const struct gsm48_imm_ass *ia = msgb_l3(msg);
struct gsm48_rrlayer *rr = &ms->rrlayer;
uint8_t ch_type, ch_subch, ch_ts;
int rc;
@ -173,6 +209,13 @@ static int modem_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
if ((ia->page_mode >> 4) == 0)
return 0;
if (rr->state != GSM48_RR_ST_CONN_PEND)
return 0;
if (!app_data.chan_req.ref_valid)
return 0;
if (memcmp(&ia->req_ref, &app_data.chan_req.ref, sizeof(ia->req_ref)))
return 0;
if (rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts) != 0) {
LOGP(DRR, LOGL_ERROR,
"%s(): rsl_dec_chan_nr(chan_nr=0x%02x) failed\n",
@ -190,9 +233,13 @@ static int modem_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
"ARFCN=%u, TS=%u, SS=%u, TSC=%u)\n", ia->req_ref.ra,
ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
ia->chan_desc.h0.tsc);
l1ctl_tx_dm_est_req_h0(ms, arfcn, RSL_CHAN_OSMO_PDCH,
ia->chan_desc.h0.tsc, GSM48_CMODE_SIGN, 0);
} else {
/* Hopping */
uint8_t maio, hsn;
uint8_t maio, hsn, ma_len;
uint16_t ma[64];
hsn = ia->chan_desc.h1.hsn;
maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);
@ -201,6 +248,22 @@ static int modem_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
"HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u)\n", ia->req_ref.ra,
ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
ia->chan_desc.h1.tsc);
for (unsigned int i = 1, j = 0; i <= 1024; i++) {
unsigned int arfcn = i & 1023;
unsigned int k;
if (~app_data.si.freq[arfcn].mask & 0x01)
continue;
k = ia->mob_alloc_len - (j >> 3) - 1;
if (ia->mob_alloc[k] & (1 << (j & 7)))
ma[ma_len++] = arfcn;
j++;
}
l1ctl_tx_dm_est_req_h1(ms, maio, hsn, &ma[0], ma_len, RSL_CHAN_OSMO_PDCH,
ia->chan_desc.h1.tsc, GSM48_CMODE_SIGN, 0);
}
const uint8_t *data = msgb_l3(msg) + sizeof(*ia) + ia->mob_alloc_len;
@ -213,6 +276,9 @@ static int modem_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
return rc;
}
/* TODO: deliver decoded params to the RLC/MAC layer */
rr->state = GSM48_RR_ST_DEDICATED;
return 0;
}
@ -313,6 +379,31 @@ static int modem_rx_rslms_rll(struct osmocom_ms *ms, struct msgb *msg)
}
}
static int modem_rx_rslms_cchan(struct osmocom_ms *ms, struct msgb *msg)
{
const struct abis_rsl_cchan_hdr *ch = msgb_l2(msg);
struct gsm48_rrlayer *rr = &ms->rrlayer;
switch (ch->c.msg_type) {
case RSL_MT_CHAN_CONF: /* RACH.conf */
if (rr->state == GSM48_RR_ST_CONN_PEND) {
const struct gsm48_req_ref *ref = (void *)&ch->data[1];
LOGP(DRSL, LOGL_NOTICE,
"Rx RACH.conf (RA=0x%02x, T1=%u, T3=%u, T2=%u)\n",
rr->cr_ra, ref->t1, ref->t3_high << 3 | ref->t3_low, ref->t2);
memcpy(&app_data.chan_req.ref, ref, sizeof(*ref));
app_data.chan_req.ref.ra = rr->cr_ra;
app_data.chan_req.ref_valid = true;
return 0;
}
/* fall-through */
default:
LOGP(DRSL, LOGL_NOTICE, "Unhandled RSLms CCHAN message "
"(msg_type 0x%02x)\n", ch->c.msg_type);
return -EINVAL;
}
}
static int modem_rslms_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
{
const struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
@ -322,6 +413,9 @@ static int modem_rslms_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
case ABIS_RSL_MDISC_RLL:
rc = modem_rx_rslms_rll((struct osmocom_ms *)ctx, msg);
break;
case ABIS_RSL_MDISC_COM_CHAN:
rc = modem_rx_rslms_cchan((struct osmocom_ms *)ctx, msg);
break;
default:
LOGP(DRSL, LOGL_NOTICE, "Unhandled RSLms message "
"(msg_discr 0x%02x)\n", rslh->msg_discr);