pespin has submitted this change. (
https://gerrit.osmocom.org/c/libosmo-gprs/+/31099 )
Change subject: rlcmac: Initial implementation of UL TBF assignment and scheduler
......................................................................
rlcmac: Initial implementation of UL TBF assignment and scheduler
This patch is another step towards a working RLC/MAC implementation. It adds:
* An initial data model with MS (gprs_rlcmac_entity) and ul_tbf.
* A UL_TBF state FSM from initial to FLOW status
* A UL_TBF assignemnt FSM, covering both 1phase and 2phase assignments.
* Triggering of UL_TBF allocation and assignment FSM when new LLC data
is pushed from upper layers.
* A scheduler generating some ctrl messages (PktResReq and UlDummyCtrlBlk)
when indicated by the network.
This patch is pushed as a WIP state since it already contains a
considerable amount of code and lots of new files, which can be
used/extended at a later point, making parallel contribution easier.
Related: OS#5500
Change-Id: I420c57a9d0b63f9c2805a7c2ae8ce85532a48eef
---
M include/osmocom/gprs/rlcmac/Makefile.am
M include/osmocom/gprs/rlcmac/rlcmac.h
A include/osmocom/gprs/rlcmac/rlcmac_enc.h
M include/osmocom/gprs/rlcmac/rlcmac_private.h
A include/osmocom/gprs/rlcmac/sched.h
A include/osmocom/gprs/rlcmac/tbf.h
A include/osmocom/gprs/rlcmac/tbf_ul.h
A include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
A include/osmocom/gprs/rlcmac/tbf_ul_fsm.h
A include/osmocom/gprs/rlcmac/types_private.h
M src/rlcmac/Makefile.am
M src/rlcmac/gre.c
M src/rlcmac/misc.c
M src/rlcmac/rlcmac.c
A src/rlcmac/rlcmac_enc.c
M src/rlcmac/rlcmac_prim.c
A src/rlcmac/sched.c
A src/rlcmac/tbf.c
A src/rlcmac/tbf_ul.c
A src/rlcmac/tbf_ul_ass_fsm.c
A src/rlcmac/tbf_ul_fsm.c
M tests/rlcmac/rlcmac_prim_test.c
M tests/rlcmac/rlcmac_prim_test.err
M tests/rlcmac/rlcmac_prim_test.ok
24 files changed, 1,549 insertions(+), 10 deletions(-)
Approvals:
Jenkins Builder: Verified
pespin: Looks good to me, approved
diff --git a/include/osmocom/gprs/rlcmac/Makefile.am
b/include/osmocom/gprs/rlcmac/Makefile.am
index e797480..c529a4e 100644
--- a/include/osmocom/gprs/rlcmac/Makefile.am
+++ b/include/osmocom/gprs/rlcmac/Makefile.am
@@ -2,7 +2,14 @@
codel.h \
gre.h \
llc_queue.h \
+ rlcmac_enc.h \
rlcmac_private.h \
+ sched.h \
+ tbf.h \
+ tbf_ul.h \
+ tbf_ul_fsm.h \
+ tbf_ul_ass_fsm.h \
+ types_private.h \
$(NULL)
rlcmac_HEADERS = \
diff --git a/include/osmocom/gprs/rlcmac/rlcmac.h b/include/osmocom/gprs/rlcmac/rlcmac.h
index d7bfb0a..2de5687 100644
--- a/include/osmocom/gprs/rlcmac/rlcmac.h
+++ b/include/osmocom/gprs/rlcmac/rlcmac.h
@@ -17,6 +17,7 @@
enum osmo_gprs_rlcmac_log_cat {
OSMO_GPRS_RLCMAC_LOGC_RLCMAC,
+ OSMO_GPRS_RLCMAC_LOGC_TBFUL,
_OSMO_GPRS_RLCMAC_LOGC_MAX,
};
diff --git a/include/osmocom/gprs/rlcmac/rlcmac_enc.h
b/include/osmocom/gprs/rlcmac/rlcmac_enc.h
new file mode 100644
index 0000000..67448c1
--- /dev/null
+++ b/include/osmocom/gprs/rlcmac/rlcmac_enc.h
@@ -0,0 +1,15 @@
+#pragma once
+
+/* RLCMAC encoding support functions */
+
+#include <stdint.h>
+
+#include <osmocom/gprs/rlcmac/csn1_defs.h>
+#include <osmocom/gprs/rlcmac/types_private.h>
+#include <osmocom/gprs/rlcmac/tbf_ul.h>
+
+#define GPRS_RLCMAC_DUMMY_VEC "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"
+
+void gprs_rlcmac_enc_prepare_pkt_ul_dummy_block(RlcMacUplink_t *block, uint32_t tlli);
+
+void gprs_rlcmac_enc_prepare_pkt_resource_req(RlcMacUplink_t *block, struct
gprs_rlcmac_ul_tbf *ul_tbf, enum gprs_rlcmac_access_type acc_type);
diff --git a/include/osmocom/gprs/rlcmac/rlcmac_private.h
b/include/osmocom/gprs/rlcmac/rlcmac_private.h
index c10b159..e838c32 100644
--- a/include/osmocom/gprs/rlcmac/rlcmac_private.h
+++ b/include/osmocom/gprs/rlcmac/rlcmac_private.h
@@ -6,10 +6,27 @@
#include <stddef.h>
#include <osmocom/core/msgb.h>
+#include <osmocom/core/tdef.h>
#include <osmocom/gprs/rlcmac/rlcmac_prim.h>
#include <osmocom/gprs/rlcmac/rlcmac.h>
+/* 3GPP TS 44.064 § 8.3 TLLI assignment procedures */
+#define GPRS_RLCMAC_TLLI_UNASSIGNED (0xffffffff)
+
+#define GPRS_RLCMAC_USF_UNUSED 0x07
+
+struct gprs_rlcmac_ul_tbf_allocation_ts {
+ bool allocated;
+ uint8_t usf;
+};
+
+struct gprs_rlcmac_ul_tbf_allocation {
+ uint8_t ul_tfi;
+ uint8_t num_ts; /* number of allocated TS */
+ struct gprs_rlcmac_ul_tbf_allocation_ts ts[8];
+};
+
extern int g_rlcmac_log_cat[_OSMO_GPRS_RLCMAC_LOGC_MAX];
#define LOGRLCMAC(lvl, fmt, args...) LOGP(g_rlcmac_log_cat[OSMO_GPRS_RLCMAC_LOGC_RLCMAC],
lvl, fmt, ## args)
@@ -31,13 +48,18 @@
osmo_gprs_rlcmac_prim_down_cb rlcmac_down_cb;
void *rlcmac_down_cb_user_data;
+ struct osmo_tdef *T_defs; /* timers controlled by RLC/MAC layer */
+
struct llist_head gre_list; /* contains (struct gprs_rlcmac_entity)->entry */
+
+ uint8_t next_ul_tbf_nr;
};
extern struct gprs_rlcmac_ctx *g_ctx;
/* rlcmac.c */
struct gprs_rlcmac_entity *gprs_rlcmac_find_entity_by_tlli(uint32_t tlli);
+int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia);
/* rlcmac_prim.c */
int gprs_rlcmac_prim_call_up_cb(struct osmo_gprs_rlcmac_prim *rlcmac_prim);
diff --git a/include/osmocom/gprs/rlcmac/sched.h b/include/osmocom/gprs/rlcmac/sched.h
new file mode 100644
index 0000000..d344aea
--- /dev/null
+++ b/include/osmocom/gprs/rlcmac/sched.h
@@ -0,0 +1,12 @@
+/* RLC/MAC scheduler, 3GPP TS 44.060 */
+#pragma once
+
+#include <stdint.h>
+
+struct gprs_rlcmac_rts_block_ind {
+ uint8_t ts;
+ uint32_t fn;
+ uint8_t usf;
+};
+
+int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_rts_block_ind *bi);
diff --git a/include/osmocom/gprs/rlcmac/tbf.h b/include/osmocom/gprs/rlcmac/tbf.h
new file mode 100644
index 0000000..df5698f
--- /dev/null
+++ b/include/osmocom/gprs/rlcmac/tbf.h
@@ -0,0 +1,25 @@
+/* TBF, 3GPP TS 44.060 */
+#pragma once
+
+#include <stdint.h>
+
+struct gprs_rlcmac_entity;
+
+enum gprs_rlcmac_tbf_direction {
+ GPRS_RLCMAC_TBF_DIR_DL,
+ GPRS_RLCMAC_TBF_DIR_UL
+};
+
+struct gprs_rlcmac_tbf {
+ struct gprs_rlcmac_entity *gre; /* backpointer */
+ enum gprs_rlcmac_tbf_direction direction;
+ const char *name;
+ uint8_t nr; /* TBF number, separate address space for DL and UL, used to identify TBF.
*/
+};
+
+void gprs_rlcmac_tbf_constructor(struct gprs_rlcmac_tbf *tbf,
+ enum gprs_rlcmac_tbf_direction direction,
+ struct gprs_rlcmac_entity *gre);
+void gprs_rlcmac_tbf_destructor(struct gprs_rlcmac_tbf *tbf);
+
+void gprs_rlcmac_tbf_free(struct gprs_rlcmac_tbf *tbf);
diff --git a/include/osmocom/gprs/rlcmac/tbf_ul.h b/include/osmocom/gprs/rlcmac/tbf_ul.h
new file mode 100644
index 0000000..8d122ae
--- /dev/null
+++ b/include/osmocom/gprs/rlcmac/tbf_ul.h
@@ -0,0 +1,57 @@
+/* Uplink TBF, 3GPP TS 44.060 */
+#pragma once
+
+#include <inttypes.h>
+
+#include <osmocom/core/msgb.h>
+
+#include <osmocom/gprs/rlcmac/tbf.h>
+#include <osmocom/gprs/rlcmac/tbf_ul_fsm.h>
+#include <osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h>
+#include <osmocom/gprs/rlcmac/sched.h>
+#include <osmocom/gprs/rlcmac/rlcmac_private.h>
+
+struct gprs_rlcmac_ul_tbf {
+ struct gprs_rlcmac_tbf tbf;
+ struct gprs_rlcmac_tbf_ul_fsm_ctx state_fsm;
+ struct gprs_rlcmac_tbf_ul_ass_fsm_ctx ul_ass_fsm;
+
+ struct gprs_rlcmac_ul_tbf_allocation cur_alloc;
+};
+
+struct gprs_rlcmac_ul_tbf *gprs_rlcmac_ul_tbf_alloc(struct gprs_rlcmac_entity *gre);
+void gprs_rlcmac_ul_tbf_free(struct gprs_rlcmac_ul_tbf *ul_tbf);
+
+bool gprs_rlcmac_ul_tbf_data_rts(const struct gprs_rlcmac_ul_tbf *ul_tbf, const struct
gprs_rlcmac_rts_block_ind *bi);
+bool gprs_rlcmac_ul_tbf_dummy_rts(const struct gprs_rlcmac_ul_tbf *ul_tbf, const struct
gprs_rlcmac_rts_block_ind *bi);
+
+struct msgb *gprs_rlcmac_ul_tbf_data_create(const struct gprs_rlcmac_ul_tbf *ul_tbf,
const struct gprs_rlcmac_rts_block_ind *bi);
+struct msgb *gprs_rlcmac_ul_tbf_dummy_create(const struct gprs_rlcmac_ul_tbf *ul_tbf);
+
+
+static inline struct gprs_rlcmac_tbf *ul_tbf_as_tbf(struct gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ return &ul_tbf->tbf;
+}
+
+static inline const struct gprs_rlcmac_tbf *ul_tbf_as_tbf_const(const struct
gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ return &ul_tbf->tbf;
+}
+
+static inline struct gprs_rlcmac_ul_tbf *tbf_as_ul_tbf(struct gprs_rlcmac_tbf *tbf)
+{
+ OSMO_ASSERT(tbf->direction == GPRS_RLCMAC_TBF_DIR_UL);
+ return (struct gprs_rlcmac_ul_tbf *)tbf;
+}
+
+static inline const struct gprs_rlcmac_ul_tbf *tbf_as_ul_tbf_const(struct gprs_rlcmac_tbf
*tbf)
+{
+ OSMO_ASSERT(tbf->direction == GPRS_RLCMAC_TBF_DIR_UL);
+ return (const struct gprs_rlcmac_ul_tbf *)tbf;
+}
+
+#define LOGPTBFUL(ul_tbf, lvl, fmt, args...) \
+ LOGP(g_rlcmac_log_cat[OSMO_GPRS_RLCMAC_LOGC_TBFUL], lvl, "TBF(UL:NR-%" PRIu8
":TLLI-%08x) " fmt, \
+ (ul_tbf)->tbf.nr, (ul_tbf)->tbf.gre->tlli, \
+ ## args)
diff --git a/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
b/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
new file mode 100644
index 0000000..28a51af
--- /dev/null
+++ b/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
@@ -0,0 +1,78 @@
+/* UL TBF Assignment FSM, 3GPP TS 44.060 */
+#pragma once
+
+#include <stdint.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/msgb.h>
+
+#include <osmocom/gprs/rlcmac/csn1_defs.h>
+#include <osmocom/gprs/rlcmac/rlcmac_private.h>
+
+struct gprs_rlcmac_ul_tbf;
+struct gprs_rlcmac_rts_block_ind;
+
+enum gprs_rlcmac_tbf_ul_ass_type {
+ GPRS_RLCMAC_TBF_UL_ASS_TYPE_1PHASE,
+ GPRS_RLCMAC_TBF_UL_ASS_TYPE_2PHASE,
+};
+
+enum gprs_rlcmac_tbf_ul_ass_fsm_states {
+ GPRS_RLCMAC_TBF_UL_ASS_ST_IDLE = 0, /* new created TBF */
+ GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_CCCH_IMM_ASS, /* wait for Immediate Assignment */
+ GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ, /* wait PDCH sched (USF) */
+ GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_PKT_UL_ASS, /* Wait for PCU to send the new assignment
*/
+ GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK, /* Wait for scheduler to send PKT CTRL ACK
*/
+ GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL, /* Completed, will update TBF and return to IDLE state
*/
+};
+
+struct gprs_rlcmac_tbf_ul_ass_fsm_ctx {
+ struct osmo_fsm_inst *fi;
+ union { /* back pointer. union used to easily access superclass from ctx */
+ struct gprs_rlcmac_tbf *tbf;
+ struct gprs_rlcmac_ul_tbf *ul_tbf;
+ };
+ enum gprs_rlcmac_tbf_ul_ass_type ass_type;
+ uint8_t rach_req_ra;
+ struct gprs_rlcmac_ul_tbf_allocation phase1_alloc;
+ struct gprs_rlcmac_ul_tbf_allocation phase2_alloc;
+ struct { /* Filled when we receive the poll; exact time here the response PKT CTL ACK is
to be transmitted: */
+ uint8_t ts;
+ uint32_t fn;
+ } sched_pkt_ctrl_ack;
+};
+
+enum tbf_ul_ass_fsm_event {
+ GPRS_RLCMAC_TBF_UL_ASS_EV_START, /* Start Uplink assignment (data: enum
gprs_rlcmac_tbf_ul_ass_type) */
+ GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS, /* (data: struct
tbf_ul_ass_ev_rx_ccch_imm_ass_ctx *) */
+ GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG, /* Generate RLC/MAC block (data: struct
tbf_ul_ass_ev_create_rlcmac_msg_ctx) */
+ GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS, /* (data: decoded PktUlAss) */
+ GPRS_RLCMAC_TBF_UL_ASS_EV_FOOBAR,
+};
+
+struct tbf_ul_ass_ev_rx_ccch_imm_ass_ctx {
+ uint8_t ts_nr;
+ const struct gsm48_imm_ass *ia;
+ const IA_RestOctets_t *iaro;
+};
+
+struct tbf_ul_ass_ev_create_rlcmac_msg_ctx {
+ uint8_t ts; /* TS where the created UL ctrl block is to be sent */
+ uint32_t fn; /* FN where the created UL ctrl block is to be sent */
+ struct msgb *msg; /* to be filled by FSM during event processing */
+};
+
+int gprs_rlcmac_tbf_ul_ass_fsm_init(void);
+void gprs_rlcmac_tbf_ul_ass_fsm_set_log_cat(int logcat);
+
+int gprs_rlcmac_tbf_ul_ass_fsm_constructor(struct gprs_rlcmac_ul_tbf *ul_tbf);
+void gprs_rlcmac_tbf_ul_ass_fsm_destructor(struct gprs_rlcmac_ul_tbf *ul_tbf);
+
+int gprs_rlcmac_tbf_ul_ass_start(struct gprs_rlcmac_ul_tbf *ul_tbf, enum
gprs_rlcmac_tbf_ul_ass_type type);
+bool gprs_rlcmac_tbf_ul_ass_pending(struct gprs_rlcmac_ul_tbf *ul_tbf);
+bool gprs_rlcmac_tbf_ul_ass_match_rach_req(struct gprs_rlcmac_ul_tbf *ul_tbf, uint8_t
ra);
+bool gprs_rlcmac_tbf_ul_ass_rts(const struct gprs_rlcmac_ul_tbf *ul_tbf, const struct
gprs_rlcmac_rts_block_ind *bi);
+struct msgb *gprs_rlcmac_tbf_ul_ass_create_rlcmac_msg(const struct gprs_rlcmac_ul_tbf
*ul_tbf,
+ const struct gprs_rlcmac_rts_block_ind *bi);
+
+enum gprs_rlcmac_tbf_ul_ass_fsm_states gprs_rlcmac_tbf_ul_ass_state(const struct
gprs_rlcmac_ul_tbf *ul_tbf);
diff --git a/include/osmocom/gprs/rlcmac/tbf_ul_fsm.h
b/include/osmocom/gprs/rlcmac/tbf_ul_fsm.h
new file mode 100644
index 0000000..7aa4b1e
--- /dev/null
+++ b/include/osmocom/gprs/rlcmac/tbf_ul_fsm.h
@@ -0,0 +1,36 @@
+/* Uplink TBF, 3GPP TS 44.060 */
+#pragma once
+
+#include <osmocom/core/fsm.h>
+
+#include <osmocom/gprs/rlcmac/rlcmac_private.h>
+
+struct gprs_rlcmac_ul_tbf;
+
+enum gprs_rlcmac_tbf_ul_fsm_states {
+ GPRS_RLCMAC_TBF_UL_ST_NEW = 0, /* new created TBF */
+ GPRS_RLCMAC_TBF_UL_ST_WAIT_ASSIGN, /* wait for Immediate Assignment */
+ GPRS_RLCMAC_TBF_UL_ST_FLOW, /* RLC/MAC flow, resource needed */
+};
+
+struct gprs_rlcmac_tbf_ul_fsm_ctx {
+ struct osmo_fsm_inst *fi;
+ union { /* back pointer. union used to easily access superclass from ctx */
+ struct gprs_rlcmac_tbf *tbf;
+ struct gprs_rlcmac_ul_tbf *ul_tbf;
+ };
+};
+
+enum tbf_ul_fsm_event {
+ GPRS_RLCMAC_TBF_UL_EV_UL_ASS_START,
+ GPRS_RLCMAC_TBF_UL_EV_UL_ASS_COMPL,
+ GPRS_RLCMAC_TBF_UL_EV_FOOBAR,
+};
+
+int gprs_rlcmac_tbf_ul_fsm_init(void);
+void gprs_rlcmac_tbf_ul_fsm_set_log_cat(int logcat);
+
+int gprs_rlcmac_tbf_ul_fsm_constructor(struct gprs_rlcmac_ul_tbf *ul_tbf);
+void gprs_rlcmac_tbf_ul_fsm_destructor(struct gprs_rlcmac_ul_tbf *ul_tbf);
+
+enum gprs_rlcmac_tbf_ul_fsm_states gprs_rlcmac_tbf_ul_state(const struct
gprs_rlcmac_ul_tbf *ul_tbf);
diff --git a/include/osmocom/gprs/rlcmac/types_private.h
b/include/osmocom/gprs/rlcmac/types_private.h
new file mode 100644
index 0000000..10852cf
--- /dev/null
+++ b/include/osmocom/gprs/rlcmac/types_private.h
@@ -0,0 +1,32 @@
+/* Types & defines from TS 44.060, TS 44.064, private extensions */
+#pragma once
+
+#include <osmocom/gprs/rlcmac/types.h>
+
+/* TS 44.060 Table 11.2.16.2 "ACCESS_TYPE" */
+enum gprs_rlcmac_access_type {
+ GPRS_RLCMAC_ACCESS_TYPE_2PHASE_ACC_REQ = 0, /* Two Phase Access Request */
+ GPRS_RLCMAC_ACCESS_TYPE_PAGE_RESP = 1, /* Page Response */
+ GPRS_RLCMAC_ACCESS_TYPE_CELL_UPD = 2, /* Cell Update */
+ GPRS_RLCMAC_ACCESS_TYPE_MM = 3, /* Mobility Management procedure */
+};
+
+/* TS 44.060 Table Table 11.2.5. "Radio Priority" */
+enum gprs_rlcmac_radio_priority {
+ GPRS_RLCMAC_RADIO_PRIORITY_1 = 0, /* Radio Priority 1 (Highest priority) */
+ GPRS_RLCMAC_RADIO_PRIORITY_2 = 1, /* Radio Priority 2 */
+ GPRS_RLCMAC_RADIO_PRIORITY_3 = 2, /* Radio Priority 3 */
+ GPRS_RLCMAC_RADIO_PRIORITY_4 = 3, /* Radio Priority 4 (Lower priority) */
+};
+
+/* TS 44.060 Table Table 12.7.2 "RLC_MODE" */
+enum gprs_rlcmac_rlc_mode {
+ GPRS_RLCMAC_RLC_MODE_ACKNOWLEDGED = 0,
+ GPRS_RLCMAC_RLC_MODE_UNACKNOWLEDGED = 1,
+};
+
+/* TS 44.060 Table Table Table 12.7.2 "LLC_PDU_TYPE" */
+enum gprs_rlcmac_llc_pdu_type {
+ GPRS_RLCMAC_LLC_PDU_TYPE_ACKNOWLEDGED = 0,
+ GPRS_RLCMAC_LLC_PDU_TYPE_UNACKNOWLEDGED = 1,
+};
diff --git a/src/rlcmac/Makefile.am b/src/rlcmac/Makefile.am
index 676abe0..fe221a2 100644
--- a/src/rlcmac/Makefile.am
+++ b/src/rlcmac/Makefile.am
@@ -10,10 +10,12 @@
AM_CFLAGS = \
-Wall \
+ $(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOCORE_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
+ $(LIBOSMOGSM_LIBS) \
$(LIBOSMOCORE_LIBS) \
$(NULL)
@@ -29,7 +31,13 @@
gre.c \
llc_queue.c \
rlcmac.c \
+ rlcmac_enc.c \
rlcmac_prim.c \
+ sched.c \
+ tbf.c \
+ tbf_ul.c \
+ tbf_ul_fsm.c \
+ tbf_ul_ass_fsm.c \
ts_44_060.c \
ts_44_064.c \
misc.c \
@@ -43,5 +51,6 @@
libosmo_gprs_rlcmac_la_LIBADD = \
$(top_builddir)/src/csn1/libosmo-csn1.la \
+ $(LIBOSMOGSM_LIBS) \
$(LIBOSMOCORE_LIBS) \
$(NULL)
diff --git a/src/rlcmac/gre.c b/src/rlcmac/gre.c
index 7acd4f6..3d8ba08 100644
--- a/src/rlcmac/gre.c
+++ b/src/rlcmac/gre.c
@@ -24,6 +24,8 @@
#include <osmocom/gprs/rlcmac/rlcmac.h>
#include <osmocom/gprs/rlcmac/rlcmac_prim.h>
#include <osmocom/gprs/rlcmac/rlcmac_private.h>
+#include <osmocom/gprs/rlcmac/tbf_ul_fsm.h>
+#include <osmocom/gprs/rlcmac/tbf_ul.h>
#include <osmocom/gprs/rlcmac/gre.h>
struct gprs_rlcmac_entity *gprs_rlcmac_entity_alloc(uint32_t tlli)
@@ -55,6 +57,8 @@
{
if (!gre)
return;
+
+ gprs_rlcmac_ul_tbf_free(gre->ul_tbf);
gprs_rlcmac_llc_queue_free(gre->llc_queue);
llist_del(&gre->entry);
talloc_free(gre);
@@ -69,7 +73,14 @@
if (rc < 0)
return rc;
- /* TODO: here a new UL TBF will be created if not available yet */
+ if (!gre->ul_tbf) {
+ /* We have new data in the queue but we have no ul_tbf. Allocate one and start UL
Assignment. */
+ gre->ul_tbf = gprs_rlcmac_ul_tbf_alloc(gre);
+ if (!gre->ul_tbf)
+ return -ENOMEM;
+ /* We always use 1phase for now... */
+ rc = gprs_rlcmac_tbf_ul_ass_start(gre->ul_tbf, GPRS_RLCMAC_TBF_UL_ASS_TYPE_1PHASE);
+ }
return rc;
}
diff --git a/src/rlcmac/misc.c b/src/rlcmac/misc.c
index 4885bbf..4edc2b9 100644
--- a/src/rlcmac/misc.c
+++ b/src/rlcmac/misc.c
@@ -18,6 +18,8 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
#include <osmocom/gprs/rlcmac/rlcmac.h>
+#include <osmocom/gprs/rlcmac/tbf_ul_fsm.h>
+#include <osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h>
int g_rlcmac_log_cat[_OSMO_GPRS_RLCMAC_LOGC_MAX] = {
[0 ... _OSMO_GPRS_RLCMAC_LOGC_MAX - 1] = DLGLOBAL
@@ -27,4 +29,9 @@
{
OSMO_ASSERT(logc < _OSMO_GPRS_RLCMAC_LOGC_MAX);
g_rlcmac_log_cat[logc] = logc_num;
+
+ if (logc == OSMO_GPRS_RLCMAC_LOGC_TBFUL) {
+ gprs_rlcmac_tbf_ul_fsm_set_log_cat(logc_num);
+ gprs_rlcmac_tbf_ul_ass_fsm_set_log_cat(logc_num);
+ }
}
diff --git a/src/rlcmac/rlcmac.c b/src/rlcmac/rlcmac.c
index 13a3e84..97516d5 100644
--- a/src/rlcmac/rlcmac.c
+++ b/src/rlcmac/rlcmac.c
@@ -21,28 +21,58 @@
#include <stdbool.h>
+#include <osmocom/gsm/rsl.h>
+
#include <osmocom/gprs/rlcmac/rlcmac.h>
#include <osmocom/gprs/rlcmac/rlcmac_prim.h>
#include <osmocom/gprs/rlcmac/rlcmac_private.h>
+#include <osmocom/gprs/rlcmac/tbf_ul_fsm.h>
+#include <osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h>
#include <osmocom/gprs/rlcmac/gre.h>
+#include <osmocom/gprs/rlcmac/tbf_ul.h>
+#include <osmocom/gprs/rlcmac/csn1_defs.h>
#define GPRS_CODEL_SLOW_INTERVAL_MS 4000
struct gprs_rlcmac_ctx *g_ctx;
+static struct osmo_tdef T_defs_rlcmac[] = {
+ { 0 } /* empty item at the end */
+};
+
int osmo_gprs_rlcmac_init(enum osmo_gprs_rlcmac_location location)
{
+ bool first_init = true;
+ int rc;
OSMO_ASSERT(location == OSMO_GPRS_RLCMAC_LOCATION_MS || location ==
OSMO_GPRS_RLCMAC_LOCATION_PCU)
- if (g_ctx)
+ if (g_ctx) {
talloc_free(g_ctx);
+ first_init = false;
+ }
g_ctx = talloc_zero(NULL, struct gprs_rlcmac_ctx);
g_ctx->cfg.location = location;
g_ctx->cfg.codel.use = true;
g_ctx->cfg.codel.interval_msec = GPRS_CODEL_SLOW_INTERVAL_MS;
+ g_ctx->T_defs = T_defs_rlcmac;
INIT_LLIST_HEAD(&g_ctx->gre_list);
+ osmo_tdefs_reset(g_ctx->T_defs);
+
+ if (first_init) {
+ rc = gprs_rlcmac_tbf_ul_fsm_init();
+ if (rc != 0) {
+ TALLOC_FREE(g_ctx);
+ return rc;
+ }
+ rc = gprs_rlcmac_tbf_ul_ass_fsm_init();
+ if (rc != 0) {
+ TALLOC_FREE(g_ctx);
+ return rc;
+ }
+ }
+
return 0;
}
@@ -71,3 +101,106 @@
}
return NULL;
}
+
+static int gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(uint8_t ts_nr, const struct
gsm48_imm_ass *ia, const IA_RestOctets_t *iaro)
+{
+ int rc = -ENOENT;
+ struct gprs_rlcmac_entity *gre;
+ struct gprs_rlcmac_ul_tbf *ul_tbf;
+ struct tbf_ul_ass_ev_rx_ccch_imm_ass_ctx d = {
+ .ts_nr = ts_nr,
+ .ia = ia,
+ .iaro = iaro
+ };
+
+ llist_for_each_entry(gre, &g_ctx->gre_list, entry) {
+ ul_tbf = gre->ul_tbf;
+ if (!ul_tbf)
+ continue;
+ if (!gprs_rlcmac_tbf_ul_ass_match_rach_req(ul_tbf, ia->req_ref.ra))
+ continue;
+ rc = osmo_fsm_inst_dispatch(ul_tbf->ul_ass_fsm.fi,
+ GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS,
+ &d);
+ break;
+ }
+ return rc;
+}
+
+int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia)
+{
+ int rc;
+ uint8_t ch_type, ch_subch, ch_ts;
+ IA_RestOctets_t iaro;
+ const uint8_t *iaro_raw = ((uint8_t *)ia) + sizeof(*ia) + ia->mob_alloc_len;
+ size_t iaro_raw_len = GSM_MACBLOCK_LEN - (sizeof(*ia) + ia->mob_alloc_len);
+
+ rc = rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch,
&ch_ts);
+ if (rc != 0) {
+ LOGRLCMAC(LOGL_ERROR, "rsl_dec_chan_nr(chan_nr=0x%02x) failed\n",
+ ia->chan_desc.chan_nr);
+ return rc;
+ }
+
+ rc = osmo_gprs_rlcmac_decode_imm_ass_ro(&iaro, iaro_raw, iaro_raw_len);
+ if (rc != 0) {
+ LOGRLCMAC(LOGL_ERROR, "Failed to decode IA Rest Octets IE\n");
+ return rc;
+ }
+
+ switch (iaro.UnionType) {
+ case 0: /* iaro.u.ll.* (IA_RestOctetsLL_t) */
+ /* TODO: iaro.u.ll.Compressed_Inter_RAT_HO_INFO_IND */
+ /* TODO: iaro.u.ll.AdditionsR13.* (IA_AdditionsR13_t) */
+ break;
+ case 1: /* iaro.u.lh.* (IA_RestOctetsLH_t) */
+ switch (iaro.u.lh.lh0x.UnionType) {
+ case 0: /* iaro.u.ll.lh0x.EGPRS_PktUlAss.* (IA_EGPRS_PktUlAss_t) */
+ rc = gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, ia, &iaro);
+ break;
+ case 1: /* iaro.u.ll.lh0x.MultiBlock_PktDlAss.* (IA_MultiBlock_PktDlAss_t) */
+ /* TODO: Alloc DL TBF */
+ break;
+ }
+ /* TODO: iaro.u.lh.AdditionsR13.* (IA_AdditionsR13_t) */
+ break;
+ case 2: /* iaro.u.hl.* (IA_RestOctetsHL_t) */
+ /* TODO: iaro.u.hl.IA_FrequencyParams (IA_FreqParamsBeforeTime_t) */
+ /* TODO: iaro.u.hl.Compressed_Inter_RAT_HO_INFO_IND */
+ /* TODO: iaro.u.hl.AdditionsR13.* (IA_AdditionsR13_t) */
+ break;
+ case 3: /* iaro.u.hh.* (IA_RestOctetsHH_t) */
+ switch (iaro.u.hh.UnionType) {
+ case 0: /* iaro.u.hh.u.UplinkDownlinkAssignment.* (IA_PacketAssignment_UL_DL_t) */
+ switch (iaro.u.hh.u.UplinkDownlinkAssignment.UnionType) {
+ case 0: /* iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.*
(Packet_Uplink_ImmAssignment_t) */
+ switch
(iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.UnionType) {
+ case 0: /*
iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.SingleBlockAllocation.*
(GPRS_SingleBlockAllocation_t) */
+ /* TODO: 2phase access support: Schedule transmit of PKT_RES_REQ on
FN=(GPRS_SingleBlockAllocation_t).TBF_STARTING_TIME */
+ LOGRLCMAC(LOGL_ERROR, "ImmAss SingleBlock (2phase access) not yet
supported!\n");
+ break;
+ case 1: /*
iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.*
(GPRS_DynamicOrFixedAllocation_t) */
+ switch
(iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.UnionType)
{
+ case 0: /*
iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.Allocation.DynamicAllocation
(DynamicAllocation_t) */
+ rc = gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, ia, &iaro);
+ break;
+ case 1: /*
iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.Allocation.FixedAllocationDummy
(guint8) */
+ rc = gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, ia, &iaro);
+ break;
+ }
+ break;
+ }
+ break;
+ case 1: /* iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Downlink_ImmAssignment*
(Packet_Downlink_ImmAssignment_t) */
+ /* TODO: Alloc DL TBF */
+ break;
+ }
+ break;
+ case 1: /* iaro.u.hh.u.SecondPartPacketAssignment.* (Second_Part_Packet_Assignment_t)
*/
+ break;
+ }
+ break;
+ }
+
+ return rc;
+}
diff --git a/src/rlcmac/rlcmac_enc.c b/src/rlcmac/rlcmac_enc.c
new file mode 100644
index 0000000..ef22f05
--- /dev/null
+++ b/src/rlcmac/rlcmac_enc.c
@@ -0,0 +1,95 @@
+/* RLC/MAC encoding helpers, 3GPP TS 44.060 */
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <osmocom/gprs/rlcmac/csn1_defs.h>
+#include <osmocom/gprs/rlcmac/rlcmac_enc.h>
+#include <osmocom/gprs/rlcmac/gre.h>
+#include <osmocom/gprs/rlcmac/tbf_ul.h>
+
+void gprs_rlcmac_enc_prepare_pkt_ul_dummy_block(RlcMacUplink_t *block, uint32_t tlli)
+{
+ Packet_Uplink_Dummy_Control_Block_t *dummy;
+
+ memset(block, 0, sizeof(*block));
+
+ dummy = &block->u.Packet_Uplink_Dummy_Control_Block;
+ dummy->MESSAGE_TYPE = OSMO_GPRS_RLCMAC_UL_MSGT_PACKET_UPLINK_DUMMY_CONTROL_BLOCK;
+ /* 10.4.7: RLC/MAC control block that does not include the optional octets of the
RLC/MAC control header: */
+ dummy->PayloadType = 0x1;
+ dummy->R = 0; /* MS sent channel request message once */
+ dummy->TLLI = tlli;
+}
+
+/* 11.2.16 Packet Resource Request */
+void gprs_rlcmac_enc_prepare_pkt_resource_req(RlcMacUplink_t *block,
+ struct gprs_rlcmac_ul_tbf *ul_tbf,
+ enum gprs_rlcmac_access_type acc_type)
+{
+ Packet_Resource_Request_t *req;
+ struct gprs_rlcmac_entity *gre = ul_tbf->tbf.gre;
+
+ memset(block, 0, sizeof(*block));
+
+ req = &block->u.Packet_Resource_Request;
+ req->MESSAGE_TYPE = OSMO_GPRS_RLCMAC_UL_MSGT_PACKET_RESOURCE_REQUEST;
+ /* 10.4.7: RLC/MAC control block that does not include the optional octets of the
RLC/MAC control header: */
+ req->PayloadType = 0x1;
+ req->R = 0; /* MS sent channel request message once */
+
+ req->Exist_ACCESS_TYPE = 1;
+ req->ACCESS_TYPE = acc_type;
+
+ req->ID.UnionType = 1; /* Use TLLI */
+ req->ID.u.TLLI = gre->tlli; /* Use TLLI */
+ req->Exist_MS_Radio_Access_capability2 = 1;
+
+ req->MS_Radio_Access_capability2.Count_MS_RA_capability_value = 1;
+ /* TODO: fill Content_t: */
+ /* req->MS_Radio_Access_capability2.MS_RA_capability_value[0].Content.* */
+
+ /* 3GPP TS 24.008 Peak Throughput Class, range 1..9 */
+ req->Channel_Request_Description.PEAK_THROUGHPUT_CLASS = 1;
+ req->Channel_Request_Description.RADIO_PRIORITY = GPRS_RLCMAC_RADIO_PRIORITY_4;
+ req->Channel_Request_Description.RLC_MODE = GPRS_RLCMAC_RLC_MODE_ACKNOWLEDGED;
+ req->Channel_Request_Description.LLC_PDU_TYPE =
GPRS_RLCMAC_LLC_PDU_TYPE_ACKNOWLEDGED;
+ req->Channel_Request_Description.RLC_OCTET_COUNT =
gprs_rlcmac_llc_queue_octets(gre->llc_queue);
+
+ /* "this field contains the SI13_CHANGE_MARK value stored by the mobile station.
+ * If the mobile station does not have a valid PSI2 or SI13 change mark for the current
cell,
+ * the mobile station shall omit this field." */
+ req->Exist_CHANGE_MARK = 0;
+ /* req->CHANGE_MARK; */
+
+ /* TODO: binary representation of the C value as specified in 3GPP TS 45.008. */
+ req->C_VALUE = 0;
+
+ /* SIGN_VAR: "This field is not present for TBF establishment using two phase
access or for
+ * a TBF in EGPRS mode" (see 3GPP TS 45.008) */
+ if (acc_type != GPRS_RLCMAC_ACCESS_TYPE_2PHASE_ACC_REQ) {
+ req->Exist_SIGN_VAR = 1;
+ req->SIGN_VAR = 0; /* TODO: calculate */
+ }
+
+ /* For element definition see sub-clause 11.2.6 - Packet Downlink Ack/Nack. */
+ /* TODO: req->I_LEVEL_TN[8]; */
+
+ req->Exist_AdditionsR99 = 0;
+ /* TODO: no req->AdditionsR99 yet */
+}
diff --git a/src/rlcmac/rlcmac_prim.c b/src/rlcmac/rlcmac_prim.c
index a2f2576..ef0dd22 100644
--- a/src/rlcmac/rlcmac_prim.c
+++ b/src/rlcmac/rlcmac_prim.c
@@ -31,11 +31,14 @@
#include <osmocom/core/logging.h>
#include <osmocom/crypt/gprs_cipher.h>
#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gprs/rlcmac/rlcmac.h>
#include <osmocom/gprs/rlcmac/rlcmac_prim.h>
#include <osmocom/gprs/rlcmac/rlcmac_private.h>
#include <osmocom/gprs/rlcmac/gre.h>
+#include <osmocom/gprs/rlcmac/tbf_ul.h>
+#include <osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h>
#define RLCMAC_MSGB_HEADROOM 0
@@ -437,8 +440,14 @@
static int rlcmac_prim_handle_l1ctl_pdch_rts_ind(struct osmo_gprs_rlcmac_prim
*rlcmac_prim)
{
- int rc = gprs_rlcmac_prim_handle_unsupported(rlcmac_prim);
- rc = 1; /* msg owned (freed) */
+ int rc;
+ struct gprs_rlcmac_rts_block_ind bi = {
+ .ts = rlcmac_prim->l1ctl.pdch_rts_ind.ts_nr,
+ .fn = rlcmac_prim->l1ctl.pdch_rts_ind.fn,
+ .usf = rlcmac_prim->l1ctl.pdch_rts_ind.usf,
+ };
+
+ rc = gprs_rlcmac_rcv_rts_block(&bi);
return rc;
}
@@ -451,8 +460,13 @@
static int rlcmac_prim_handle_l1ctl_ccch_data_ind(struct osmo_gprs_rlcmac_prim
*rlcmac_prim)
{
- int rc = gprs_rlcmac_prim_handle_unsupported(rlcmac_prim);
- rc = 1; /* msg owned (freed) */
+ /* TODO: check if it's IMM_ASS: */
+ int rc;
+
+ if (rlcmac_prim->l1ctl.ccch_data_ind.data[2] == GSM48_MT_RR_IMM_ASS)
+ rc = gprs_rlcmac_handle_ccch_imm_ass((struct gsm48_imm_ass
*)rlcmac_prim->l1ctl.ccch_data_ind.data);
+ else
+ rc = -ENOTSUP;
return rc;
}
diff --git a/src/rlcmac/sched.c b/src/rlcmac/sched.c
new file mode 100644
index 0000000..93dc50f
--- /dev/null
+++ b/src/rlcmac/sched.c
@@ -0,0 +1,136 @@
+/* RLC/MAC scheduler, 3GPP TS 44.060 */
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/msgb.h>
+
+#include <osmocom/gprs/rlcmac/rlcmac_private.h>
+#include <osmocom/gprs/rlcmac/sched.h>
+#include <osmocom/gprs/rlcmac/gre.h>
+#include <osmocom/gprs/rlcmac/tbf_ul.h>
+#include <osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h>
+
+struct tbf_sched_ctrl_candidates {
+ struct gprs_rlcmac_ul_tbf *ul_ass;
+};
+
+static void get_ctrl_msg_tbf_candidates(const struct gprs_rlcmac_rts_block_ind *bi,
+ struct tbf_sched_ctrl_candidates *tbfs)
+{
+
+ struct gprs_rlcmac_entity *gre;
+ struct gprs_rlcmac_ul_tbf *ul_tbf;
+
+ /* Iterate over UL TBFs: */
+ llist_for_each_entry(gre, &g_ctx->gre_list, entry) {
+ if (!gre->ul_tbf)
+ continue;
+ ul_tbf = gre->ul_tbf;
+ if (gprs_rlcmac_tbf_ul_ass_rts(ul_tbf, bi))
+ tbfs->ul_ass = ul_tbf;
+ }
+
+ /* TODO: Iterate over DL TBFs: */
+}
+
+static struct gprs_rlcmac_ul_tbf *find_requested_ul_tbf_for_data(const struct
gprs_rlcmac_rts_block_ind *bi)
+{
+ struct gprs_rlcmac_entity *gre;
+ llist_for_each_entry(gre, &g_ctx->gre_list, entry) {
+ if (!gre->ul_tbf)
+ continue;
+ if (gprs_rlcmac_ul_tbf_data_rts(gre->ul_tbf, bi))
+ return gre->ul_tbf;
+ }
+ return NULL;
+}
+
+static struct gprs_rlcmac_ul_tbf *find_requested_ul_tbf_for_dummy(const struct
gprs_rlcmac_rts_block_ind *bi)
+{
+ struct gprs_rlcmac_entity *gre;
+ llist_for_each_entry(gre, &g_ctx->gre_list, entry) {
+ if (!gre->ul_tbf)
+ continue;
+ if (gprs_rlcmac_ul_tbf_dummy_rts(gre->ul_tbf, bi))
+ return gre->ul_tbf;
+ }
+ return NULL;
+}
+
+static struct msgb *sched_select_ctrl_msg(const struct gprs_rlcmac_rts_block_ind *bi,
+ struct tbf_sched_ctrl_candidates *tbfs)
+{
+ struct msgb *msg = NULL;
+ if (tbfs->ul_ass)
+ msg = gprs_rlcmac_tbf_ul_ass_create_rlcmac_msg(tbfs->ul_ass, bi);
+ return msg;
+}
+
+static struct msgb *sched_select_ul_data_msg(const struct gprs_rlcmac_rts_block_ind *bi)
+{
+ struct gprs_rlcmac_ul_tbf *ul_tbf;
+
+ ul_tbf = find_requested_ul_tbf_for_data(bi);
+ if (!ul_tbf) {
+ LOGRLCMAC(LOGL_DEBUG, "(ts=%u,fn=%u,usf=%u) No Uplink TBF available to transmit
RLC/MAC Ul Data Block\n",
+ bi->ts, bi->fn, bi->usf);
+ return NULL;
+ }
+ return gprs_rlcmac_ul_tbf_data_create(ul_tbf, bi);
+}
+
+static struct msgb *sched_select_ul_dummy_ctrl_blk(const struct gprs_rlcmac_rts_block_ind
*bi)
+{
+ struct gprs_rlcmac_ul_tbf *ul_tbf;
+
+ ul_tbf = find_requested_ul_tbf_for_dummy(bi);
+ if (!ul_tbf) {
+ LOGRLCMAC(LOGL_DEBUG, "(ts=%u,fn=%u,usf=%u) No Uplink TBF available to transmit
RLC/MAC Ul Dummy Ctrl Block\n",
+ bi->ts, bi->fn, bi->usf);
+ return NULL;
+ }
+
+ return gprs_rlcmac_ul_tbf_dummy_create(ul_tbf);
+}
+
+int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_rts_block_ind *bi)
+{
+ struct msgb *msg = NULL;
+ struct tbf_sched_ctrl_candidates tbf_cand = {0};
+
+ get_ctrl_msg_tbf_candidates(bi, &tbf_cand);
+
+ if ((msg = sched_select_ctrl_msg(bi, &tbf_cand)))
+ goto tx_msg;
+
+ if ((msg = sched_select_ul_data_msg(bi)))
+ goto tx_msg;
+
+ /* Prio 3: send dummy control message (or nothing depending on EXT_UTBF_NODATA) */
+ if ((msg = sched_select_ul_dummy_ctrl_blk(bi)))
+ goto tx_msg;
+
+ /* Nothing to transmit */
+ return 0;
+tx_msg:
+ /* TODO: transmit msg to lower layer (L1CTL?) */
+ return 0;
+}
diff --git a/src/rlcmac/tbf.c b/src/rlcmac/tbf.c
new file mode 100644
index 0000000..ea15d69
--- /dev/null
+++ b/src/rlcmac/tbf.c
@@ -0,0 +1,43 @@
+/* TBF as per 3GPP TS 44.064 */
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/gprs/rlcmac/tbf.h>
+#include <osmocom/gprs/rlcmac/tbf_ul.h>
+
+void gprs_rlcmac_tbf_constructor(struct gprs_rlcmac_tbf *tbf,
+ enum gprs_rlcmac_tbf_direction direction,
+ struct gprs_rlcmac_entity *gre)
+{
+ tbf->gre = gre;
+ tbf->direction = direction;
+}
+
+void gprs_rlcmac_tbf_destructor(struct gprs_rlcmac_tbf *tbf)
+{
+
+}
+
+void gprs_rlcmac_tbf_free(struct gprs_rlcmac_tbf *tbf)
+{
+ if (tbf->direction == GPRS_RLCMAC_TBF_DIR_UL)
+ gprs_rlcmac_ul_tbf_free(tbf_as_ul_tbf(tbf));
+ /* else: TODO dl_tbf not yet implemented */
+}
diff --git a/src/rlcmac/tbf_ul.c b/src/rlcmac/tbf_ul.c
new file mode 100644
index 0000000..54ecd34
--- /dev/null
+++ b/src/rlcmac/tbf_ul.c
@@ -0,0 +1,134 @@
+/* Uplink TBF as per 3GPP TS 44.064 */
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/bitvec.h>
+
+#include <osmocom/gprs/rlcmac/tbf_ul.h>
+#include <osmocom/gprs/rlcmac/rlcmac_enc.h>
+#include <osmocom/gprs/rlcmac/gre.h>
+
+struct gprs_rlcmac_ul_tbf *gprs_rlcmac_ul_tbf_alloc(struct gprs_rlcmac_entity *gre)
+{
+ struct gprs_rlcmac_ul_tbf *ul_tbf;
+ int rc;
+
+ ul_tbf = talloc_zero(gre, struct gprs_rlcmac_ul_tbf);
+ if (!ul_tbf)
+ return NULL;
+
+ gprs_rlcmac_tbf_constructor(ul_tbf_as_tbf(ul_tbf), GPRS_RLCMAC_TBF_DIR_UL, gre);
+
+ rc = gprs_rlcmac_tbf_ul_fsm_constructor(ul_tbf);
+ if (rc < 0)
+ goto err_tbf_destruct;
+
+ rc = gprs_rlcmac_tbf_ul_ass_fsm_constructor(ul_tbf);
+ if (rc < 0)
+ goto err_state_fsm_destruct;
+
+ ul_tbf->tbf.nr = g_ctx->next_ul_tbf_nr++;
+
+ return ul_tbf;
+
+err_state_fsm_destruct:
+ gprs_rlcmac_tbf_destructor(ul_tbf_as_tbf(ul_tbf));
+err_tbf_destruct:
+ gprs_rlcmac_tbf_destructor(ul_tbf_as_tbf(ul_tbf));
+ talloc_free(ul_tbf);
+ return NULL;
+}
+
+void gprs_rlcmac_ul_tbf_free(struct gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ if (!ul_tbf)
+ return;
+
+ gprs_rlcmac_tbf_ul_ass_fsm_destructor(ul_tbf);
+ gprs_rlcmac_tbf_ul_fsm_destructor(ul_tbf);
+
+ gprs_rlcmac_tbf_destructor(ul_tbf_as_tbf(ul_tbf));
+ talloc_free(ul_tbf);
+}
+
+/* Used by the scheduler to find out whether an Uplink Dummy Control Block can be
transmitted. If
+ * true, it will potentially call gprs_rlcmac_ul_tbf_dummy_create() to generate a new
dummy message to transmit. */
+bool gprs_rlcmac_ul_tbf_dummy_rts(const struct gprs_rlcmac_ul_tbf *ul_tbf, const struct
gprs_rlcmac_rts_block_ind *bi)
+{
+ if (!ul_tbf->cur_alloc.ts[bi->ts].allocated)
+ return false;
+ if (ul_tbf->cur_alloc.ts[bi->ts].usf != bi->usf)
+ return false;
+ return true;
+}
+
+/* Used by the scheduler to find out whether there's data to be transmitted at the
requested time. If
+ * true, it will potentially call gprs_rlcmac_ul_tbf_data_create() to generate a new data
message to transmit. */
+bool gprs_rlcmac_ul_tbf_data_rts(const struct gprs_rlcmac_ul_tbf *ul_tbf, const struct
gprs_rlcmac_rts_block_ind *bi)
+{
+ enum gprs_rlcmac_tbf_ul_fsm_states st;
+
+ if (!gprs_rlcmac_ul_tbf_dummy_rts(ul_tbf, bi))
+ return false;
+
+ st = gprs_rlcmac_tbf_ul_state(ul_tbf);
+ return (st == GPRS_RLCMAC_TBF_UL_ST_FLOW);
+}
+
+struct msgb *gprs_rlcmac_ul_tbf_dummy_create(const struct gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ struct msgb *msg;
+ struct bitvec bv;
+ RlcMacUplink_t ul_block;
+ int rc;
+
+ OSMO_ASSERT(ul_tbf);
+
+ msg = msgb_alloc(GSM_MACBLOCK_LEN, "pkt_ul_dummy_ctrl_blk");
+ if (!msg)
+ return NULL;
+
+ /* Initialize a bit vector that uses allocated msgb as the data buffer. */
+ bv = (struct bitvec){
+ .data = msgb_put(msg, GSM_MACBLOCK_LEN),
+ .data_len = GSM_MACBLOCK_LEN,
+ };
+ bitvec_unhex(&bv, GPRS_RLCMAC_DUMMY_VEC);
+
+ gprs_rlcmac_enc_prepare_pkt_ul_dummy_block(&ul_block, ul_tbf->tbf.gre->tlli);
+ rc = osmo_gprs_rlcmac_encode_uplink(&bv, &ul_block);
+ if (rc < 0) {
+ LOGPTBFUL(ul_tbf, LOGL_ERROR, "Encoding of Packet Uplink Dummy Control Block
failed (%d)\n", rc);
+ goto free_ret;
+ }
+
+ return msg;
+
+free_ret:
+ msgb_free(msg);
+ return NULL;
+}
+
+struct msgb *gprs_rlcmac_ul_tbf_data_create(const struct gprs_rlcmac_ul_tbf *ul_tbf,
const struct gprs_rlcmac_rts_block_ind *bi)
+{
+ LOGPTBFUL(ul_tbf, LOGL_ERROR, "(ts=%u,fn=%u,usf=%u) TODO: implement dequeue from
LLC\n",
+ bi->ts, bi->fn, bi->usf);
+ return NULL;
+}
diff --git a/src/rlcmac/tbf_ul_ass_fsm.c b/src/rlcmac/tbf_ul_ass_fsm.c
new file mode 100644
index 0000000..1130187
--- /dev/null
+++ b/src/rlcmac/tbf_ul_ass_fsm.c
@@ -0,0 +1,445 @@
+/* TBF as per 3GPP TS 44.064 */
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <errno.h>
+#include <talloc.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/bitvec.h>
+
+#include <osmocom/gprs/rlcmac/types.h>
+#include <osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h>
+#include <osmocom/gprs/rlcmac/tbf_ul.h>
+#include <osmocom/gprs/rlcmac/gre.h>
+#include <osmocom/gprs/rlcmac/sched.h>
+#include <osmocom/gprs/rlcmac/csn1_defs.h>
+#include <osmocom/gprs/rlcmac/rlcmac_enc.h>
+
+#define X(s) (1 << (s))
+
+static const struct value_string tbf_ul_ass_fsm_event_names[] = {
+ { GPRS_RLCMAC_TBF_UL_ASS_EV_START, "START" },
+ { GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS, "RX_CCCH_IMM_ASS" },
+ { GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG, "CREATE_RLCMAC_MSG" },
+ { GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS, "RX_PKT_UL_ASS" },
+ { GPRS_RLCMAC_TBF_UL_ASS_EV_FOOBAR, "FOOBAR" },
+ { 0, NULL }
+};
+
+static const struct osmo_tdef_state_timeout tbf_ul_ass_fsm_timeouts[32] = {
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_IDLE] = { },
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_CCCH_IMM_ASS] = { },
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ] = { },
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_PKT_UL_ASS] = { },
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK] = { },
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL] = { },
+};
+
+/* Transition to a state, using the T timer defined in tbf_fsm_timeouts.
+ * The actual timeout value is in turn obtained from conn->T_defs.
+ * Assumes local variable fi exists. */
+ #define tbf_ul_ass_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, \
+ tbf_ul_ass_fsm_timeouts, \
+ g_ctx->T_defs, \
+ -1)
+
+static struct msgb *create_pkt_resource_req(const struct gprs_rlcmac_tbf_ul_ass_fsm_ctx
*ctx,
+ struct tbf_ul_ass_ev_create_rlcmac_msg_ctx *d)
+{
+ struct msgb *msg;
+ struct bitvec bv;
+ RlcMacUplink_t ul_block;
+ int rc;
+
+ msg = msgb_alloc(GSM_MACBLOCK_LEN, "pkt_res_req");
+ if (!msg)
+ return NULL;
+
+ /* Initialize a bit vector that uses allocated msgb as the data buffer. */
+ bv = (struct bitvec){
+ .data = msgb_put(msg, GSM_MACBLOCK_LEN),
+ .data_len = GSM_MACBLOCK_LEN,
+ };
+ bitvec_unhex(&bv, GPRS_RLCMAC_DUMMY_VEC);
+
+ gprs_rlcmac_enc_prepare_pkt_resource_req(&ul_block, ctx->ul_tbf,
GPRS_RLCMAC_ACCESS_TYPE_2PHASE_ACC_REQ);
+ rc = osmo_gprs_rlcmac_encode_uplink(&bv, &ul_block);
+ if (rc < 0) {
+ LOGPTBFUL(ctx->ul_tbf, LOGL_ERROR, "Encoding of Packet Resource Req failed
(%d)\n", rc);
+ goto free_ret;
+ }
+
+ return msg;
+
+free_ret:
+ msgb_free(msg);
+ return NULL;
+}
+
+/* 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 submit_rach_req(struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx)
+{
+ struct osmo_gprs_rlcmac_prim *rlcmac_prim;
+ ctx->rach_req_ra = gen_chan_req(ctx->ass_type ==
GPRS_RLCMAC_TBF_UL_ASS_TYPE_2PHASE);
+
+ LOGPFSML(ctx->fi, LOGL_INFO, "Send RACH.req ra=0x%02x\n",
ctx->rach_req_ra);
+ rlcmac_prim = gprs_rlcmac_prim_alloc_l1ctl_rach8_req(ctx->rach_req_ra);
+ return gprs_rlcmac_prim_call_down_cb(rlcmac_prim);
+}
+
+static int handle_imm_ass(struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx, const struct
tbf_ul_ass_ev_rx_ccch_imm_ass_ctx *d)
+{
+ switch (d->iaro->UnionType) {
+ case 1: /* d->iaro->u.lh.* (IA_RestOctetsLH_t) */
+ switch (d->iaro->u.lh.lh0x.UnionType) {
+ case 0: /* d->iaro->u.ll.lh0x.EGPRS_PktUlAss.* (IA_EGPRS_PktUlAss_t) */
+ return -ENOTSUP; /* TODO */
+ }
+ case 3: /* d->iaro->u.hh.* (IA_RestOctetsHH_t) */
+ switch (d->iaro->u.hh.UnionType) {
+ case 0: /* d->iaro->u.hh.u.UplinkDownlinkAssignment.*
(IA_PacketAssignment_UL_DL_t) */
+ switch (d->iaro->u.hh.u.UplinkDownlinkAssignment.UnionType) {
+ case 0: /*
d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.*
(Packet_Uplink_ImmAssignment_t) */
+ switch
(d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.UnionType)
{
+ case 0: /*
d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.SingleBlockAllocation.*
(GPRS_SingleBlockAllocation_t) */
+ /* TODO: 2phase access support: Schedule transmit of PKT_RES_REQ on
FN=(GPRS_SingleBlockAllocation_t).TBF_STARTING_TIME */
+ LOGPFSML(ctx->fi, LOGL_ERROR, "ImmAss SingleBlock (2phase access) not yet
supported!\n");
+ return -ENOTSUP;
+ case 1: /*
d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.*
(GPRS_DynamicOrFixedAllocation_t) */
+ //ctx->ul_tbf->tx_cs =
d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.CHANNEL_CODING_COMMAND
+ 1;
+ //LOGPFSML(ctx->fi, LOGL_INFO, "ImmAss initial CS=%s\n",
gprs_rlcmac_mcs_name(ctx->ul_tbf->tx_cs));
+ switch
(d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.UnionType)
{
+ case 0: /*
d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.Allocation.DynamicAllocation
(DynamicAllocation_t) */
+ /* TODO: 2phase access support: Schedule transmit of PKT_RES_REQ on
FN=(GPRS_SingleBlockAllocation_t).TBF_STARTING_TIME */
+ ctx->phase1_alloc.ts[d->ts_nr].allocated = true;
+ ctx->phase1_alloc.ts[d->ts_nr].usf =
d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.Allocation.DynamicAllocation.USF;
+ ctx->phase1_alloc.num_ts = 1;
+ LOGPFSML(ctx->fi, LOGL_INFO, "ImmAss DynamicAlloc (1phase access) ts_nr=%u
usf=%u\n", d->ts_nr, ctx->phase1_alloc.ts[d->ts_nr].usf);
+ return 0;
+ case 1: /*
d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.Allocation.FixedAllocationDummy
(guint8) */
+ return -ENOTSUP;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ OSMO_ASSERT(0);
+ return -EFAULT;
+}
+
+static void st_idle_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_ass_fsm_ctx
*)fi->priv;
+
+ /* Reset state: */
+ memset(&ctx->phase1_alloc, 0, sizeof(ctx->phase1_alloc));
+ memset(&ctx->phase2_alloc, 0, sizeof(ctx->phase2_alloc));
+ memset(&ctx->sched_pkt_ctrl_ack, 0, sizeof(ctx->sched_pkt_ctrl_ack));
+}
+
+static void st_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_ass_fsm_ctx
*)fi->priv;
+ switch (event) {
+ case GPRS_RLCMAC_TBF_UL_ASS_EV_START:
+ /* Inform the main TBF state about the assignment starting: */
+ osmo_fsm_inst_dispatch(ctx->ul_tbf->state_fsm.fi,
GPRS_RLCMAC_TBF_UL_EV_UL_ASS_START, NULL);
+ ctx->ass_type = *(enum gprs_rlcmac_tbf_ul_ass_type *)data;
+ submit_rach_req(ctx);
+ tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_CCCH_IMM_ASS);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_wait_ccch_imm_ass(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_ass_fsm_ctx
*)fi->priv;
+ const struct tbf_ul_ass_ev_rx_ccch_imm_ass_ctx *ev_rx_ccch_imm_ass_ctx;
+
+ switch (event) {
+ case GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS:
+ ev_rx_ccch_imm_ass_ctx = data;
+ if (handle_imm_ass(ctx, ev_rx_ccch_imm_ass_ctx) < 0)
+ return;
+ if (ctx->ass_type == GPRS_RLCMAC_TBF_UL_ASS_TYPE_1PHASE)
+ tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL);
+ else
+ tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_sched_pkt_res_req(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_ass_fsm_ctx
*)fi->priv;
+ struct tbf_ul_ass_ev_create_rlcmac_msg_ctx *data_ctx;
+ switch (event) {
+ case GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG:
+ data_ctx = (struct tbf_ul_ass_ev_create_rlcmac_msg_ctx *)data;
+ LOGPFSML(fi, LOGL_ERROR, "TODO: create PKT RES REQ...\n");
+ data_ctx->msg = create_pkt_resource_req(ctx, data_ctx);
+ if (!data_ctx->msg)
+ return;
+ tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_PKT_UL_ASS);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_wait_pkt_ul_ass(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ //struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_ass_fsm_ctx
*)fi->priv;
+ switch (event) {
+ case GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS:
+ // TODO: fill ctx->phase2_alloc with contents from pkt_ul_ass
+ // TODO: what to do if Pkt_ul_ass is "reject"? need to check spec, depending
on cause.
+ tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_sched_pkt_ctrl_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ //struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_ass_fsm_ctx
*)fi->priv;
+ struct tbf_ul_ass_ev_create_rlcmac_msg_ctx *data_ctx;
+
+ switch (event) {
+ case GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG:
+ data_ctx = (struct tbf_ul_ass_ev_create_rlcmac_msg_ctx *)data;
+ LOGPFSML(fi, LOGL_ERROR, "TODO: create PKT CTRL ACK...\n");
+ //data_ctx->msg = create_packet_ctrl_ack(ctx, data_ctx);
+ data_ctx->msg = NULL;
+ if (!data_ctx->msg)
+ return;
+ tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_compl_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_ass_fsm_ctx
*)fi->priv;
+
+ /* Update TBF with allocated content: */
+ if (ctx->ass_type == GPRS_RLCMAC_TBF_UL_ASS_TYPE_1PHASE)
+ memcpy(&ctx->ul_tbf->cur_alloc, &ctx->phase1_alloc,
sizeof(ctx->phase1_alloc));
+ else
+ memcpy(&ctx->ul_tbf->cur_alloc, &ctx->phase2_alloc,
sizeof(ctx->phase1_alloc));
+ /* Inform the main TBF state about the assignment completed: */
+ osmo_fsm_inst_dispatch(ctx->ul_tbf->state_fsm.fi,
GPRS_RLCMAC_TBF_UL_EV_UL_ASS_COMPL, NULL);
+ /* Go back to IDLE state. */
+ tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_IDLE);
+}
+
+static struct osmo_fsm_state tbf_ul_ass_fsm_states[] = {
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_IDLE] = {
+ .in_event_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_EV_START),
+ .out_state_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_CCCH_IMM_ASS),
+ .name = "IDLE",
+ .onenter = st_idle_on_enter,
+ .action = st_idle,
+ },
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_CCCH_IMM_ASS] = {
+ .in_event_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS),
+ .out_state_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ) |
+ X(GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL),
+ .name = "WAIT_CCCH_IMM_ASS",
+ .action = st_wait_ccch_imm_ass,
+ },
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ] = {
+ .in_event_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG),
+ .out_state_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_PKT_UL_ASS),
+ .name = "SCHED_PKT_RES_REQ",
+ .action = st_sched_pkt_res_req,
+ },
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_PKT_UL_ASS] = {
+ .in_event_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS),
+ .out_state_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK),
+ .name = "WAIT_PKT_UL_ASS",
+ .action = st_wait_pkt_ul_ass,
+ },
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK] = {
+ .in_event_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG),
+ .out_state_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL),
+ .name = "SCHED_PKT_CTRL_ACK",
+ .action = st_sched_pkt_ctrl_ack,
+ },
+ [GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL] = {
+ .in_event_mask = 0,
+ .out_state_mask =
+ X(GPRS_RLCMAC_TBF_UL_ASS_ST_IDLE),
+ .name = "COMPLETED",
+ .onenter = st_compl_on_enter,
+ },
+};
+
+
+static int tbf_ul_ass_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+ struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_ass_fsm_ctx
*)fi->priv;
+ switch (fi->T) {
+ case -2001:
+ LOGPTBFUL(ctx->ul_tbf, LOGL_NOTICE, "releasing due to PACCH assignment
timeout.\n");
+ /* fall-through */
+ case 3169:
+ case 3195:
+ gprs_rlcmac_ul_tbf_free(ctx->ul_tbf);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+ return 0;
+}
+
+static struct osmo_fsm tbf_ul_ass_fsm = {
+ .name = "UL_TBF_ASS",
+ .states = tbf_ul_ass_fsm_states,
+ .num_states = ARRAY_SIZE(tbf_ul_ass_fsm_states),
+ .timer_cb = tbf_ul_ass_fsm_timer_cb,
+ .log_subsys = DLGLOBAL, /* updated dynamically through
gprs_rlcmac_tbf_ul_ass_fsm_set_log_cat() */
+ .event_names = tbf_ul_ass_fsm_event_names,
+};
+
+int gprs_rlcmac_tbf_ul_ass_fsm_init(void)
+{
+ return osmo_fsm_register(&tbf_ul_ass_fsm);
+}
+
+void gprs_rlcmac_tbf_ul_ass_fsm_set_log_cat(int logcat)
+{
+ tbf_ul_ass_fsm.log_subsys = logcat;
+}
+
+int gprs_rlcmac_tbf_ul_ass_fsm_constructor(struct gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = &ul_tbf->ul_ass_fsm;
+ ctx->ul_tbf = ul_tbf;
+ ctx->fi = osmo_fsm_inst_alloc(&tbf_ul_ass_fsm, ul_tbf, ctx, LOGL_INFO, NULL);
+ if (!ctx->fi)
+ return -ENODATA;
+
+ return 0;
+}
+
+void gprs_rlcmac_tbf_ul_ass_fsm_destructor(struct gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = &ul_tbf->ul_ass_fsm;
+ osmo_fsm_inst_free(ctx->fi);
+ ctx->fi = NULL;
+}
+
+int gprs_rlcmac_tbf_ul_ass_start(struct gprs_rlcmac_ul_tbf *ul_tbf, enum
gprs_rlcmac_tbf_ul_ass_type type)
+{
+ int rc;
+ rc = osmo_fsm_inst_dispatch(ul_tbf->ul_ass_fsm.fi,
+ GPRS_RLCMAC_TBF_UL_ASS_EV_START,
+ &type);
+ return rc;
+}
+
+bool gprs_rlcmac_tbf_ul_ass_pending(struct gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ return ul_tbf->ul_ass_fsm.fi->state != GPRS_RLCMAC_TBF_UL_ASS_ST_IDLE;
+}
+
+bool gprs_rlcmac_tbf_ul_ass_match_rach_req(struct gprs_rlcmac_ul_tbf *ul_tbf, uint8_t
ra)
+{
+ return ul_tbf->ul_ass_fsm.fi->state == GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_CCCH_IMM_ASS
&&
+ ul_tbf->ul_ass_fsm.rach_req_ra == ra;
+}
+
+enum gprs_rlcmac_tbf_ul_ass_fsm_states gprs_rlcmac_tbf_ul_ass_state(const struct
gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ const struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = &ul_tbf->ul_ass_fsm;
+ return ctx->fi->state;
+}
+
+bool gprs_rlcmac_tbf_ul_ass_rts(const struct gprs_rlcmac_ul_tbf *ul_tbf, const struct
gprs_rlcmac_rts_block_ind *bi)
+{
+ const struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = &ul_tbf->ul_ass_fsm;
+
+ switch (ctx->fi->state) {
+ case GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ:
+ return (ctx->phase1_alloc.ts[bi->ts].allocated &&
+ ctx->phase1_alloc.ts[bi->ts].usf == bi->usf);
+ case GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK:
+ return (ctx->sched_pkt_ctrl_ack.ts == bi->ts &&
+ ctx->sched_pkt_ctrl_ack.fn == bi->fn);
+ default:
+ return false;
+ };
+}
+
+struct msgb *gprs_rlcmac_tbf_ul_ass_create_rlcmac_msg(const struct gprs_rlcmac_ul_tbf
*ul_tbf,
+ const struct gprs_rlcmac_rts_block_ind *bi)
+{
+ int rc;
+ struct tbf_ul_ass_ev_create_rlcmac_msg_ctx data_ctx = {
+ .ts = bi->ts,
+ .fn = bi->fn,
+ .msg = NULL,
+ };
+
+ rc = osmo_fsm_inst_dispatch(ul_tbf->ul_ass_fsm.fi,
+ GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG,
+ &data_ctx);
+ if (rc != 0 || !data_ctx.msg)
+ return NULL;
+ return data_ctx.msg;
+}
diff --git a/src/rlcmac/tbf_ul_fsm.c b/src/rlcmac/tbf_ul_fsm.c
new file mode 100644
index 0000000..0078846
--- /dev/null
+++ b/src/rlcmac/tbf_ul_fsm.c
@@ -0,0 +1,198 @@
+/* TBF as per 3GPP TS 44.064 */
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <talloc.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/core/fsm.h>
+
+#include <osmocom/gprs/rlcmac/tbf_ul_fsm.h>
+#include <osmocom/gprs/rlcmac/tbf_ul.h>
+#include <osmocom/gprs/rlcmac/gre.h>
+
+#define X(s) (1 << (s))
+
+static const struct value_string tbf_ul_fsm_event_names[] = {
+ { GPRS_RLCMAC_TBF_UL_EV_UL_ASS_START, "UL_ASS_START" },
+ { GPRS_RLCMAC_TBF_UL_EV_UL_ASS_COMPL, "UL_ASS_COMPL" },
+ { GPRS_RLCMAC_TBF_UL_EV_FOOBAR, "FOOBAR" },
+ { 0, NULL }
+};
+
+static const struct osmo_tdef_state_timeout tbf_ul_fsm_timeouts[32] = {
+ [GPRS_RLCMAC_TBF_UL_ST_NEW] = { },
+ [GPRS_RLCMAC_TBF_UL_ST_WAIT_ASSIGN] = { },
+ [GPRS_RLCMAC_TBF_UL_ST_FLOW] = { },
+};
+
+/* Transition to a state, using the T timer defined in tbf_fsm_timeouts.
+ * The actual timeout value is in turn obtained from conn->T_defs.
+ * Assumes local variable fi exists. */
+ #define tbf_ul_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, \
+ tbf_ul_fsm_timeouts, \
+ g_ctx->T_defs, \
+ -1)
+
+static uint8_t ul_tbf_ul_slotmask(struct gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ uint8_t i;
+ uint8_t ul_slotmask = 0;
+
+ for (i = 0; i < 8; i++) {
+ if (ul_tbf->cur_alloc.ts[i].allocated)
+ ul_slotmask |= (1 << i);
+ }
+
+ return ul_slotmask;
+}
+
+static int configure_ul_tbf(struct gprs_rlcmac_tbf_ul_fsm_ctx *ctx)
+{
+ struct osmo_gprs_rlcmac_prim *rlcmac_prim;
+ uint8_t ul_slotmask = ul_tbf_ul_slotmask(ctx->ul_tbf);
+
+ LOGPFSML(ctx->fi, LOGL_INFO, "Send L1CTL-CF_UL_TBF.req
ul_slotmask=0x%02x\n", ul_slotmask);
+ rlcmac_prim = gprs_rlcmac_prim_alloc_l1ctl_cfg_ul_tbf_req(ctx->tbf->nr,
ul_slotmask);
+ return gprs_rlcmac_prim_call_down_cb(rlcmac_prim);
+}
+
+static void st_new(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ //struct gprs_rlcmac_tbf_ul_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_fsm_ctx
*)fi->priv;
+ switch (event) {
+ case GPRS_RLCMAC_TBF_UL_EV_UL_ASS_START:
+ tbf_ul_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ST_WAIT_ASSIGN);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_wait_assign(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gprs_rlcmac_tbf_ul_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_fsm_ctx
*)fi->priv;
+ switch (event) {
+ case GPRS_RLCMAC_TBF_UL_EV_UL_ASS_COMPL:
+ /* Configure UL TBF on the lower MAC side: */
+ configure_ul_tbf(ctx);
+ tbf_ul_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ST_FLOW);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void st_flow(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ //struct gprs_rlcmac_tbf_ul_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_fsm_ctx
*)fi->priv;
+ switch (event) {
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static struct osmo_fsm_state tbf_ul_fsm_states[] = {
+ [GPRS_RLCMAC_TBF_UL_ST_NEW] = {
+ .in_event_mask =
+ X(GPRS_RLCMAC_TBF_UL_EV_UL_ASS_START),
+ .out_state_mask =
+ X(GPRS_RLCMAC_TBF_UL_ST_WAIT_ASSIGN) |
+ X(GPRS_RLCMAC_TBF_UL_ST_FLOW),
+ .name = "NEW",
+ .action = st_new,
+ },
+ [GPRS_RLCMAC_TBF_UL_ST_WAIT_ASSIGN] = {
+ .in_event_mask =
+ X(GPRS_RLCMAC_TBF_UL_EV_UL_ASS_COMPL),
+ .out_state_mask =
+ X(GPRS_RLCMAC_TBF_UL_ST_FLOW),
+ .name = "ASSIGN",
+ .action = st_wait_assign,
+ },
+ [GPRS_RLCMAC_TBF_UL_ST_FLOW] = {
+ .in_event_mask =
+ X(GPRS_RLCMAC_TBF_UL_EV_FOOBAR),
+ .out_state_mask =
+ X(GPRS_RLCMAC_TBF_UL_ST_WAIT_ASSIGN),
+ .name = "FLOW",
+ .action = st_flow,
+ },
+};
+
+static int tbf_ul_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+ struct gprs_rlcmac_tbf_ul_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_fsm_ctx
*)fi->priv;
+ switch (fi->T) {
+ case -2001:
+ LOGPTBFUL(ctx->ul_tbf, LOGL_NOTICE, "releasing due to PACCH assignment
timeout.\n");
+ /* fall-through */
+ case 3169:
+ case 3195:
+ gprs_rlcmac_ul_tbf_free(ctx->ul_tbf);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+ return 0;
+}
+
+static struct osmo_fsm tbf_ul_fsm = {
+ .name = "UL_TBF",
+ .states = tbf_ul_fsm_states,
+ .num_states = ARRAY_SIZE(tbf_ul_fsm_states),
+ .timer_cb = tbf_ul_fsm_timer_cb,
+ .log_subsys = DLGLOBAL, /* updated dynamically through
gprs_rlcmac_tbf_ul_fsm_set_log_cat() */
+ .event_names = tbf_ul_fsm_event_names,
+};
+
+int gprs_rlcmac_tbf_ul_fsm_init(void)
+{
+ return osmo_fsm_register(&tbf_ul_fsm);
+}
+
+void gprs_rlcmac_tbf_ul_fsm_set_log_cat(int logcat)
+{
+ tbf_ul_fsm.log_subsys = logcat;
+}
+
+int gprs_rlcmac_tbf_ul_fsm_constructor(struct gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ struct gprs_rlcmac_tbf_ul_fsm_ctx *ctx = &ul_tbf->state_fsm;
+ ctx->ul_tbf = ul_tbf;
+ ctx->fi = osmo_fsm_inst_alloc(&tbf_ul_fsm, ul_tbf, ctx, LOGL_INFO, NULL);
+ if (!ctx->fi)
+ return -ENODATA;
+
+ return 0;
+}
+
+void gprs_rlcmac_tbf_ul_fsm_destructor(struct gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ struct gprs_rlcmac_tbf_ul_fsm_ctx *ctx = &ul_tbf->state_fsm;
+ osmo_fsm_inst_free(ctx->fi);
+ ctx->fi = NULL;
+}
+
+enum gprs_rlcmac_tbf_ul_fsm_states gprs_rlcmac_tbf_ul_state(const struct
gprs_rlcmac_ul_tbf *ul_tbf)
+{
+ const struct gprs_rlcmac_tbf_ul_fsm_ctx *ctx = &ul_tbf->state_fsm;
+ return ctx->fi->state;
+}
diff --git a/tests/rlcmac/rlcmac_prim_test.c b/tests/rlcmac/rlcmac_prim_test.c
index 9347b01..fb12f05 100644
--- a/tests/rlcmac/rlcmac_prim_test.c
+++ b/tests/rlcmac/rlcmac_prim_test.c
@@ -27,6 +27,8 @@
static void *tall_ctx = NULL;
+uint8_t last_rach_req_ra = 0;
+
/**
MS-SGSN LLC (Mobile Station - Serving GPRS Support Node Logical Link Control) SAPI: GPRS
Mobility Management
Address field SAPI: LLGMM
@@ -143,7 +145,19 @@
switch (rlcmac_prim->oph.sap) {
case OSMO_GPRS_RLCMAC_SAP_L1CTL:
- printf("%s(): Rx %s\n", __func__, pdu_name);
+ switch (OSMO_PRIM_HDR(&rlcmac_prim->oph)) {
+ case OSMO_PRIM(OSMO_GPRS_RLCMAC_L1CTL_RACH, PRIM_OP_REQUEST):
+ last_rach_req_ra = rlcmac_prim->l1ctl.rach_req.ra;
+ printf("%s(): Rx %s ra=0x%02x\n", __func__, pdu_name, last_rach_req_ra);
+ break;
+ case OSMO_PRIM(OSMO_GPRS_RLCMAC_L1CTL_CFG_UL_TBF, PRIM_OP_REQUEST):
+ printf("%s(): Rx %s ul_tbf_nr=%u ul_slotmask=0x%02x\n", __func__, pdu_name,
+ rlcmac_prim->l1ctl.cfg_ul_tbf_req.ul_tbf_nr,
+ rlcmac_prim->l1ctl.cfg_ul_tbf_req.ul_slotmask);
+ break;
+ default:
+ printf("%s(): Rx %s\n", __func__, pdu_name);
+ }
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
@@ -177,11 +191,11 @@
rc = osmo_gprs_rlcmac_prim_upper_down(rlcmac_prim);
OSMO_ASSERT(sizeof(ccch_imm_ass_pkt_ul_tbf_normal) == GSM_MACBLOCK_LEN);
+ ccch_imm_ass_pkt_ul_tbf_normal[7] = last_rach_req_ra; /* Update RA to match */
rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_ccch_data_ind(0,
ccch_imm_ass_pkt_ul_tbf_normal);
rc = osmo_gprs_rlcmac_prim_lower_up(rlcmac_prim);
- /* This now fails because it's not yet implemented: */
- OSMO_ASSERT(rc != 0);
+ OSMO_ASSERT(rc == 0);
printf("=== %s end ===\n", __func__);
}
diff --git a/tests/rlcmac/rlcmac_prim_test.err b/tests/rlcmac/rlcmac_prim_test.err
index f9268b1..7e75164 100644
--- a/tests/rlcmac/rlcmac_prim_test.err
+++ b/tests/rlcmac/rlcmac_prim_test.err
@@ -1,4 +1,17 @@
DLGLOBAL INFO Rx from upper layers: GRR-UNITDATA.request
DLGLOBAL INFO TLLI=0x00002342 not found, creating entity on the fly
+DLGLOBAL INFO UL_TBF{NEW}: Allocated
+DLGLOBAL INFO UL_TBF_ASS{IDLE}: Allocated
+DLGLOBAL INFO UL_TBF_ASS{IDLE}: Received Event START
+DLGLOBAL INFO UL_TBF{NEW}: Received Event UL_ASS_START
+DLGLOBAL INFO UL_TBF{NEW}: state_chg to ASSIGN
+DLGLOBAL INFO UL_TBF_ASS{IDLE}: Send RACH.req ra=0x7e
+DLGLOBAL INFO UL_TBF_ASS{IDLE}: state_chg to WAIT_CCCH_IMM_ASS
DLGLOBAL INFO Rx from lower layers: L1CTL-CCCH_DATA.indication
-DLGLOBAL ERROR Unsupported rlcmac_prim! L1CTL-CCCH_DATA.indication
+DLGLOBAL INFO UL_TBF_ASS{WAIT_CCCH_IMM_ASS}: Received Event RX_CCCH_IMM_ASS
+DLGLOBAL INFO UL_TBF_ASS{WAIT_CCCH_IMM_ASS}: ImmAss DynamicAlloc (1phase access) ts_nr=7
usf=0
+DLGLOBAL INFO UL_TBF_ASS{WAIT_CCCH_IMM_ASS}: state_chg to COMPLETED
+DLGLOBAL INFO UL_TBF{ASSIGN}: Received Event UL_ASS_COMPL
+DLGLOBAL INFO UL_TBF{ASSIGN}: Send L1CTL-CF_UL_TBF.req ul_slotmask=0x80
+DLGLOBAL INFO UL_TBF{ASSIGN}: state_chg to FLOW
+DLGLOBAL INFO UL_TBF_ASS{COMPLETED}: state_chg to IDLE
diff --git a/tests/rlcmac/rlcmac_prim_test.ok b/tests/rlcmac/rlcmac_prim_test.ok
index 3deb5e9..030743e 100644
--- a/tests/rlcmac/rlcmac_prim_test.ok
+++ b/tests/rlcmac/rlcmac_prim_test.ok
@@ -1,2 +1,4 @@
=== test_ul_tbf_attach start ===
+test_rlcmac_prim_down_cb(): Rx L1CTL-RACH.request ra=0x7e
+test_rlcmac_prim_down_cb(): Rx L1CTL-CFG_UL_TBF.request ul_tbf_nr=0 ul_slotmask=0x80
=== test_ul_tbf_attach end ===
--
To view, visit
https://gerrit.osmocom.org/c/libosmo-gprs/+/31099
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: libosmo-gprs
Gerrit-Branch: master
Gerrit-Change-Id: I420c57a9d0b63f9c2805a7c2ae8ce85532a48eef
Gerrit-Change-Number: 31099
Gerrit-PatchSet: 17
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-CC: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: merged