pespin has submitted this change. ( 
https://gerrit.osmocom.org/c/libosmo-gprs/+/31751 )

Change subject: rlcmac: ul_tbf: Implement support for TBF Starting Time
......................................................................

rlcmac: ul_tbf: Implement support for TBF Starting Time

While reworking tbf_ul_ass_fsm, avoid being in "ASSIGN" state while
waiting to send Pkt Ctrl Ack. The PCU is free to ask the TBF to transmit
data before receiving Pkt Ctrl Ack; the time where it can start
transmitting data is actually controlled by TBF Starting Time.

Change-Id: Id81f16743f2c464e01caf27ba2eb8c0fc715fe8a
---
M include/osmocom/gprs/rlcmac/rlcmac_dec.h
M include/osmocom/gprs/rlcmac/rlcmac_private.h
M include/osmocom/gprs/rlcmac/sched.h
M include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
M src/rlcmac/pdch_ul_controller.c
M src/rlcmac/rlcmac.c
M src/rlcmac/rlcmac_dec.c
M src/rlcmac/rlcmac_prim.c
M src/rlcmac/sched.c
M src/rlcmac/tbf_ul_ass_fsm.c
M tests/rlcmac/rlcmac_prim_test.err
11 files changed, 239 insertions(+), 53 deletions(-)

Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, but someone else must approve
  pespin: Looks good to me, approved




diff --git a/include/osmocom/gprs/rlcmac/rlcmac_dec.h 
b/include/osmocom/gprs/rlcmac/rlcmac_dec.h
index ea92a0f..f707dcb 100644
--- a/include/osmocom/gprs/rlcmac/rlcmac_dec.h
+++ b/include/osmocom/gprs/rlcmac/rlcmac_dec.h
@@ -46,3 +46,7 @@
 int gprs_rlcmac_decode_gprs_acknack_bits(const Ack_Nack_Description_t *desc,
                                         struct bitvec *bits, int *bsn_begin, 
int *bsn_end,
                                         struct gprs_rlcmac_rlc_ul_window *ulw);
+
+uint32_t TBF_StartingTime_to_fn(const StartingTime_t *tbf_start_time, uint32_t 
curr_fn);
+uint32_t TBF_Starting_Frame_Number_to_fn(const Starting_Frame_Number_t 
*tbf_start_fn, uint32_t curr_fn);
+
diff --git a/include/osmocom/gprs/rlcmac/rlcmac_private.h 
b/include/osmocom/gprs/rlcmac/rlcmac_private.h
index e2d2494..cd03066 100644
--- a/include/osmocom/gprs/rlcmac/rlcmac_private.h
+++ b/include/osmocom/gprs/rlcmac/rlcmac_private.h
@@ -88,7 +88,7 @@
 struct gprs_rlcmac_entity *gprs_rlcmac_find_entity_by_tlli(uint32_t tlli);
 struct gprs_rlcmac_dl_tbf *gprs_rlcmac_find_dl_tbf_by_tfi(uint8_t dl_tfi);
 struct gprs_rlcmac_ul_tbf *gprs_rlcmac_find_ul_tbf_by_tfi(uint8_t ul_tfi);
-int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia);
+int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia, uint32_t 
fn);
 int gprs_rlcmac_handle_bcch_si13(const struct gsm48_system_information_type_13 
*si13);
 int gprs_rlcmac_handle_gprs_dl_block(const struct osmo_gprs_rlcmac_prim 
*rlcmac_prim,
                                     enum gprs_rlcmac_coding_scheme cs);
diff --git a/include/osmocom/gprs/rlcmac/sched.h 
b/include/osmocom/gprs/rlcmac/sched.h
index c7fa82a..18fbe7d 100644
--- a/include/osmocom/gprs/rlcmac/sched.h
+++ b/include/osmocom/gprs/rlcmac/sched.h
@@ -12,3 +12,23 @@
 uint32_t rrbp2fn(uint32_t cur_fn, uint8_t rrbp);

 int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_rts_block_ind *bi);
+
+static inline bool fn_valid(uint32_t fn)
+{
+       uint32_t f = fn % 13;
+       return f == 0 || f == 4 || f == 8;
+}
+
+#define GSM_MAX_FN_THRESH (GSM_MAX_FN >> 1)
+/* 0: equal, -1: fn1 BEFORE fn2, 1: fn1 AFTER fn2 */
+static inline int fn_cmp(uint32_t fn1, uint32_t fn2)
+{
+       if (fn1 == fn2)
+               return 0;
+       /* FN1 goes before FN2: */
+       if ((fn1 < fn2 && (fn2 - fn1) < GSM_MAX_FN_THRESH) ||
+           (fn1 > fn2 && (fn1 - fn2) > GSM_MAX_FN_THRESH))
+               return -1;
+       /* FN1 goes after FN2: */
+       return 1;
+}
diff --git a/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h 
b/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
index c5a785d..9026459 100644
--- a/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
+++ b/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
@@ -20,9 +20,10 @@
 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_WAIT_TBF_STARTING_TIME1,      /* Wait for Tbf 
Starting Time (1phase) */
        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_WAIT_TBF_STARTING_TIME2,      /* Wait for Tbf 
Starting Time (2phase) */
        GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL, /* Completed, will update TBF and 
return to IDLE state */
 };

@@ -37,6 +38,8 @@
        uint8_t rach_req_ra;
        struct gprs_rlcmac_ul_tbf_allocation phase1_alloc;
        struct gprs_rlcmac_ul_tbf_allocation phase2_alloc;
+       bool tbf_starting_time_exists;
+       uint32_t tbf_starting_time;
        /* Number of packet resource request transmitted (T3168) */
        unsigned int pkt_res_req_proc_attempts;
 };
@@ -46,12 +49,14 @@
        GPRS_RLCMAC_TBF_UL_ASS_EV_START_DIRECT_2PHASE, /* Start Uplink 
assignment directly into 2phase from an older UL TBF */
        GPRS_RLCMAC_TBF_UL_ASS_EV_START_FROM_DL_TBF, /* Uplink assignment 
requested by DL TBF ACK/NACK, wait to receive Pkt Ul Ass on its PACCH */
        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_TBF_STARTING_TIME, /* Scheduler ticking 
reaches TBF Starting Time */
        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: struct 
tbf_ul_ass_ev_create_rlcmac_msg_ctx) */
 };

 struct tbf_ul_ass_ev_rx_ccch_imm_ass_ctx {
        uint8_t ts_nr;
+       uint32_t fn;
        const struct gsm48_imm_ass *ia;
        const IA_RestOctets_t *iaro;
 };
@@ -80,6 +85,8 @@

 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_waiting_tbf_starting_time(const struct 
gprs_rlcmac_ul_tbf *ul_tbf);
+void gprs_rlcmac_tbf_ul_ass_fn_tick(const struct gprs_rlcmac_ul_tbf *ul_tbf, 
uint32_t fn, uint8_t ts_nr);
 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);
diff --git a/src/rlcmac/pdch_ul_controller.c b/src/rlcmac/pdch_ul_controller.c
index 7a3b753..731caf0 100644
--- a/src/rlcmac/pdch_ul_controller.c
+++ b/src/rlcmac/pdch_ul_controller.c
@@ -26,6 +26,7 @@
 #include <osmocom/gprs/rlcmac/pdch_ul_controller.h>
 #include <osmocom/gprs/rlcmac/rlcmac_private.h>
 #include <osmocom/gprs/rlcmac/types_private.h>
+#include <osmocom/gprs/rlcmac/sched.h>

 /* TS 44.060 Table 10.4.5.1 states maximum RRBP is N + 26. Give extra space 
for time diff between Tx and Rx? */
 #define MAX_FN_RESERVED (27 + 50)
@@ -39,20 +40,6 @@
        { 0, NULL }
 };

-#define GSM_MAX_FN_THRESH (GSM_MAX_FN >> 1)
-/* 0: equal, -1: fn1 BEFORE fn2, 1: fn1 AFTER fn2 */
-static inline int fn_cmp(uint32_t fn1, uint32_t fn2)
-{
-       if (fn1 == fn2)
-               return 0;
-       /* FN1 goes before FN2: */
-       if ((fn1 < fn2 && (fn2 - fn1) < GSM_MAX_FN_THRESH) ||
-           (fn1 > fn2 && (fn1 - fn2) > GSM_MAX_FN_THRESH))
-               return -1;
-       /* FN1 goes after FN2: */
-       return 1;
-}
-
 struct gprs_rlcmac_pdch_ulc *gprs_rlcmac_pdch_ulc_alloc(void *ctx, uint8_t 
ts_nr)
 {
        struct gprs_rlcmac_pdch_ulc *ulc;
diff --git a/src/rlcmac/rlcmac.c b/src/rlcmac/rlcmac.c
index 3b30fb6..4647fff 100644
--- a/src/rlcmac/rlcmac.c
+++ b/src/rlcmac/rlcmac.c
@@ -165,12 +165,13 @@
        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)
+static int gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(uint8_t ts_nr, uint32_t fn, 
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 = {
+               .fn = fn,
                .ts_nr = ts_nr,
                .ia = ia,
                .iaro = iaro
@@ -190,7 +191,7 @@
        return rc;
 }

-static int gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(uint8_t ts_nr, const struct 
gsm48_imm_ass *ia, const IA_RestOctets_t *iaro)
+static int gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(uint8_t ts_nr, uint32_t fn, 
const struct gsm48_imm_ass *ia, const IA_RestOctets_t *iaro)
 {
        int rc;
        struct gprs_rlcmac_entity *gre;
@@ -224,7 +225,7 @@
        return rc;
 }

-int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia)
+int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia, uint32_t 
fn)
 {
        int rc;
        uint8_t ch_type, ch_subch, ch_ts;
@@ -253,10 +254,10 @@
        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);
+                       rc = gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, fn, 
ia, &iaro);
                        break;
                case 1: /* iaro.u.ll.lh0x.MultiBlock_PktDlAss.* 
(IA_MultiBlock_PktDlAss_t) */
-                       rc = gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(ch_ts, ia, 
&iaro);
+                       rc = gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(ch_ts, fn, 
ia, &iaro);
                        break;
                }
                /* TODO: iaro.u.lh.AdditionsR13.* (IA_AdditionsR13_t) */
@@ -279,17 +280,17 @@
                                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);
+                                               rc = 
gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, fn, 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);
+                                               rc = 
gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, fn, ia, &iaro);
                                                break;
                                        }
                                        break;
                                }
                                break;
                        case 1: /* 
iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Downlink_ImmAssignment* 
(Packet_Downlink_ImmAssignment_t) */
-                               rc = 
gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(ch_ts, ia, &iaro);
+                               rc = 
gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(ch_ts, fn, ia, &iaro);
                                break;
                        }
                        break;
diff --git a/src/rlcmac/rlcmac_dec.c b/src/rlcmac/rlcmac_dec.c
index fa88c26..8129d30 100644
--- a/src/rlcmac/rlcmac_dec.c
+++ b/src/rlcmac/rlcmac_dec.c
@@ -22,11 +22,14 @@
 #include <stdint.h>

 #include <osmocom/core/logging.h>
+#include <osmocom/gsm/gsm0502.h>
+#include <osmocom/gsm/gsm_utils.h>

 #include <osmocom/gprs/rlcmac/rlcmac_private.h>
 #include <osmocom/gprs/rlcmac/rlcmac_dec.h>
 #include <osmocom/gprs/rlcmac/rlc.h>
 #include <osmocom/gprs/rlcmac/rlc_window_ul.h>
+#include <osmocom/gprs/rlcmac/sched.h>

 #define LENGTH_TO_END 255
 /*!
@@ -422,3 +425,47 @@

        return num_blocks;
 }
+
+/* 12.21 Starting Frame Number Description */
+uint32_t TBF_StartingTime_to_fn(const StartingTime_t *tbf_start_time, uint32_t 
curr_fn)
+{
+       const struct gsm_time g_time = {
+               .t1 = tbf_start_time->N32,
+               .t2 = tbf_start_time->N51,
+               .t3 = tbf_start_time->N26
+       };
+       return gsm_gsmtime2fn(&g_time);
+
+}
+
+/* 12.21.2 Relative Frame Number Encoding */
+static uint32_t k_to_fn(uint16_t k, uint32_t curr_fn)
+{
+       uint32_t fn = 0;
+
+       switch (k % 3) {
+       case 0:
+       case 1:
+               fn = GSM_TDMA_FN_SUM(curr_fn, 4 + 4 * k + (k / 3));
+               if (!fn_valid(fn))
+                       GSM_TDMA_FN_INC(fn);
+               break;
+       case 2:
+               fn = GSM_TDMA_FN_SUM(curr_fn, 5 + 4 * k + (k / 3));
+               break;
+       }
+       OSMO_ASSERT(fn_valid(fn));
+       return fn;
+}
+
+uint32_t TBF_Starting_Frame_Number_to_fn(const Starting_Frame_Number_t 
*tbf_start_fn, uint32_t curr_fn)
+{
+       switch (tbf_start_fn->UnionType) {
+       case 0: /* 12.21.1 Absolute Frame Number Encoding */
+               return TBF_StartingTime_to_fn(&tbf_start_fn->u.StartingTime, 
curr_fn);
+       case 1: /* 12.21.2 Relative Frame Number Encoding  */
+               return k_to_fn(tbf_start_fn->u.k, curr_fn);
+       default:
+               OSMO_ASSERT(0);
+       }
+}
diff --git a/src/rlcmac/rlcmac_prim.c b/src/rlcmac/rlcmac_prim.c
index 8cf53ba..2b3e8b2 100644
--- a/src/rlcmac/rlcmac_prim.c
+++ b/src/rlcmac/rlcmac_prim.c
@@ -504,7 +504,8 @@

        switch (rlcmac_prim->l1ctl.ccch_data_ind.data[2]) {
        case GSM48_MT_RR_IMM_ASS:
-               rc = gprs_rlcmac_handle_ccch_imm_ass((struct gsm48_imm_ass 
*)rlcmac_prim->l1ctl.ccch_data_ind.data);
+               rc = gprs_rlcmac_handle_ccch_imm_ass((struct gsm48_imm_ass 
*)rlcmac_prim->l1ctl.ccch_data_ind.data,
+                                                    
rlcmac_prim->l1ctl.ccch_data_ind.fn);
                break;
        case GSM48_MT_RR_SYSINFO_13:
                rc = gprs_rlcmac_handle_bcch_si13((struct 
gsm48_system_information_type_13 *)rlcmac_prim->l1ctl.ccch_data_ind.data);
diff --git a/src/rlcmac/sched.c b/src/rlcmac/sched.c
index 6ec76c7..0431631 100644
--- a/src/rlcmac/sched.c
+++ b/src/rlcmac/sched.c
@@ -41,12 +41,6 @@
        struct gprs_rlcmac_ul_tbf *ul_ass;      /* PCU grants USF/SBA: transmit 
Pkt Res Req (2phase access)*/
 };

-static inline bool fn_valid(uint32_t fn)
-{
-       uint32_t f = fn % 13;
-       return f == 0 || f == 4 || f == 8;
-}
-
 uint32_t rrbp2fn(uint32_t cur_fn, uint8_t rrbp)
 {
        uint32_t poll_fn;
@@ -210,7 +204,7 @@
                return msg;
        }
        if (tbfs->poll_ul_ass) {
-               msg = 
gprs_rlcmac_tbf_ul_ass_create_rlcmac_msg(tbfs->poll_ul_ass, bi);
+               msg = gprs_rlcmac_ul_tbf_create_pkt_ctrl_ack(tbfs->poll_ul_ass);
                if (msg)
                        return msg;
        }
@@ -260,6 +254,15 @@
        return gprs_rlcmac_ul_tbf_dummy_create(ul_tbf);
 }

+static void rts_tick(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 && 
gprs_rlcmac_tbf_ul_ass_waiting_tbf_starting_time(gre->ul_tbf))
+                       gprs_rlcmac_tbf_ul_ass_fn_tick(gre->ul_tbf, bi->fn, 
bi->ts);
+       }
+}
+
 int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_rts_block_ind *bi)
 {
        struct msgb *msg = NULL;
@@ -267,6 +270,8 @@
        struct osmo_gprs_rlcmac_prim *rlcmac_prim_tx;
        int rc = 0;

+       rts_tick(bi);
+
        get_ctrl_msg_tbf_candidates(bi, &tbf_cand);

        if ((msg = sched_select_ctrl_msg(bi, &tbf_cand)))
diff --git a/src/rlcmac/tbf_ul_ass_fsm.c b/src/rlcmac/tbf_ul_ass_fsm.c
index e2775be..48c1bf8 100644
--- a/src/rlcmac/tbf_ul_ass_fsm.c
+++ b/src/rlcmac/tbf_ul_ass_fsm.c
@@ -24,6 +24,8 @@
 #include <osmocom/core/tdef.h>
 #include <osmocom/core/fsm.h>
 #include <osmocom/core/bitvec.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/gsm0502.h>

 #include <osmocom/gprs/rlcmac/types.h>
 #include <osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h>
@@ -32,6 +34,7 @@
 #include <osmocom/gprs/rlcmac/sched.h>
 #include <osmocom/gprs/rlcmac/csn1_defs.h>
 #include <osmocom/gprs/rlcmac/rlcmac_enc.h>
+#include <osmocom/gprs/rlcmac/rlcmac_dec.h>
 #include <osmocom/gprs/rlcmac/pdch_ul_controller.h>

 #define X(s) (1 << (s))
@@ -39,8 +42,9 @@
 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_START_DIRECT_2PHASE, "START_DIRECT_2PHASE" 
},
-       { GPRS_RLCMAC_TBF_UL_ASS_EV_START_FROM_DL_TBF, "START_FROM_DL_TBF" },
+       { GPRS_RLCMAC_TBF_UL_ASS_EV_START_FROM_DL_TBF,  "START_FROM_DL_TBF" },
        { GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS,    "RX_CCCH_IMM_ASS" },
+       { GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME,  "TBF_STARTING_TIME" },
        { 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" },
        { 0, NULL }
@@ -49,9 +53,10 @@
 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_WAIT_TBF_STARTING_TIME1] = { },
        [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ] = { },
        [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_PKT_UL_ASS] = { .T = 3168 },
-       [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK] = { },
+       [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2] = { },
        [GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL] = { },
 };

@@ -141,6 +146,10 @@
                                        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;
+                                       ctx->tbf_starting_time_exists = 
d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.Exist_TBF_STARTING_TIME;
+                                       if (ctx->tbf_starting_time_exists)
+                                               ctx->tbf_starting_time = 
TBF_StartingTime_to_fn(&d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.TBF_STARTING_TIME,
+                                                                               
                d->fn);
                                        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) */
@@ -181,7 +190,11 @@
                case 1: /* Dynamic Allocation (Dynamic_Allocation_t) */
                        if 
(ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.Exist_UPLINK_TFI_ASSIGNMENT)
                                ctx->phase2_alloc.ul_tfi = 
ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.UPLINK_TFI_ASSIGNMENT;
-                       /* TODO: P0, PR_MODE, USF_GRANULARITY, 
RLC_DATA_BLOCKS_GRANTED, TBF_Starting_Time */
+                       /* TODO: P0, PR_MODE, USF_GRANULARITY, 
RLC_DATA_BLOCKS_GRANTED */
+                       ctx->tbf_starting_time_exists = 
ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.Exist_TBF_Starting_Time;
+                       if (ctx->tbf_starting_time_exists)
+                               ctx->tbf_starting_time = 
TBF_Starting_Frame_Number_to_fn(&ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.TBF_Starting_Time,
+                                                                               
         d->fn);
                        switch 
(ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.UnionType) {
                        case 0: /* Timeslot_Allocation_t */
                                ts_alloc = 
&ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.u.Timeslot_Allocation[0];
@@ -271,6 +284,42 @@
                ev_rx_ccch_imm_ass_ctx = data;
                if (handle_imm_ass(ctx, ev_rx_ccch_imm_ass_ctx) < 0)
                        return;
+               if (ctx->tbf_starting_time_exists &&
+                   fn_cmp(ctx->tbf_starting_time, ev_rx_ccch_imm_ass_ctx->fn) 
> 0) {
+                       tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1);
+                       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_wait_tbf_starting_time1(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->tbf_starting_time_exists &&
+                   fn_cmp(ctx->tbf_starting_time, ev_rx_ccch_imm_ass_ctx->fn) 
> 0) {
+                       tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1);
+                       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;
+       case GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME:
                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
@@ -317,7 +366,11 @@
                        
gprs_rlcmac_pdch_ulc_reserve(g_ctx->sched.ulc[d->ts_nr], poll_fn,
                                                
GPRS_RLCMAC_PDCH_ULC_POLL_UL_ASS,
                                                ul_tbf_as_tbf(ctx->ul_tbf));
-                       tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK);
+               }
+
+               if (ctx->tbf_starting_time_exists &&
+                   fn_cmp(ctx->tbf_starting_time, d->fn) > 0) {
+                       tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2);
                } else {
                        tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL);
                }
@@ -327,17 +380,34 @@
        }
 }

-static void st_sched_pkt_ctrl_ack(struct osmo_fsm_inst *fi, uint32_t event, 
void *data)
+static void st_wait_tbf_starting_time2(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;
+       struct tbf_ul_ass_ev_rx_pkt_ul_ass_ctx *d;
+       int rc;

        switch (event) {
-       case GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG:
-               data_ctx = (struct tbf_ul_ass_ev_create_rlcmac_msg_ctx *)data;
-               data_ctx->msg = 
gprs_rlcmac_ul_tbf_create_pkt_ctrl_ack(ctx->ul_tbf);
-               if (!data_ctx->msg)
-                       return;
+       case GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS:
+               d = data;
+               rc = handle_pkt_ul_ass(ctx, d);
+               if (rc < 0)
+                       LOGPFSML(fi, LOGL_ERROR, "Rx Pkt Ul Ass: failed to 
parse!\n");
+               // TODO: what to do if Pkt_ul_ass is "reject"? need to check 
spec, depending on cause.
+               /* If RRBP contains valid data, schedule a response (PKT 
CONTROL ACK or PKT RESOURCE REQ). */
+               if (d->dl_block->SP) {
+                       uint32_t poll_fn = rrbp2fn(d->fn, d->dl_block->RRBP);
+                       
gprs_rlcmac_pdch_ulc_reserve(g_ctx->sched.ulc[d->ts_nr], poll_fn,
+                                               
GPRS_RLCMAC_PDCH_ULC_POLL_UL_ASS,
+                                               ul_tbf_as_tbf(ctx->ul_tbf));
+               }
+
+               if (ctx->tbf_starting_time_exists &&
+                   fn_cmp(ctx->tbf_starting_time, d->fn) > 0) {
+                       tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2);
+               } else {
+                       tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL);
+               }
+       case GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME:
                tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL);
                break;
        default:
@@ -378,11 +448,23 @@
                .in_event_mask =
                        X(GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS),
                .out_state_mask =
+                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1) |
                        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_WAIT_TBF_STARTING_TIME1] = {
+               .in_event_mask =
+                       X(GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS) |
+                       X(GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME),
+               .out_state_mask =
+                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1) |
+                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ) |
+                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL),
+               .name = "WAIT_TBF_STARTING_TIME1",
+               .action = st_wait_tbf_starting_time1,
+       },
        [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ] = {
                .in_event_mask =
                        X(GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG),
@@ -396,18 +478,21 @@
                        X(GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS),
                .out_state_mask =
                        X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ) |
-                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK) |
+                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2) |
                        X(GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL),
                .name = "WAIT_PKT_UL_ASS",
                .action = st_wait_pkt_ul_ass,
        },
-       [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK] = {
+       [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2] = {
                .in_event_mask =
-                       X(GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG),
+                       X(GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS) |
+                       X(GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME),
                .out_state_mask =
+                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ) |
+                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2) |
                        X(GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL),
-               .name = "SCHED_PKT_CTRL_ACK",
-               .action = st_sched_pkt_ctrl_ack,
+               .name = "WAIT_TBF_STARTING_TIME2",
+               .action = st_wait_tbf_starting_time2,
        },
        [GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL] = {
                .in_event_mask = 0,
@@ -539,6 +624,23 @@
                ul_tbf->ul_ass_fsm.rach_req_ra == ra;
 }

+bool gprs_rlcmac_tbf_ul_ass_waiting_tbf_starting_time(const struct 
gprs_rlcmac_ul_tbf *ul_tbf)
+{
+       return ul_tbf->ul_ass_fsm.fi->state == 
GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1 ||
+              ul_tbf->ul_ass_fsm.fi->state == 
GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2;
+}
+
+/* The scheduled ticks the new FN, which may trigger changes internally if TBF 
Starting Time is reached */
+void gprs_rlcmac_tbf_ul_ass_fn_tick(const struct gprs_rlcmac_ul_tbf *ul_tbf, 
uint32_t fn, uint8_t ts_nr)
+{
+       OSMO_ASSERT(gprs_rlcmac_tbf_ul_ass_waiting_tbf_starting_time(ul_tbf));
+       OSMO_ASSERT(ul_tbf->ul_ass_fsm.tbf_starting_time_exists);
+       if (fn != ul_tbf->ul_ass_fsm.tbf_starting_time)
+               return;
+
+       osmo_fsm_inst_dispatch(ul_tbf->ul_ass_fsm.fi, 
GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME, NULL);
+}
+
 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;
diff --git a/tests/rlcmac/rlcmac_prim_test.err 
b/tests/rlcmac/rlcmac_prim_test.err
index af14349..5d997dd 100644
--- a/tests/rlcmac/rlcmac_prim_test.err
+++ b/tests/rlcmac/rlcmac_prim_test.err
@@ -659,16 +659,14 @@
 DLGLOBAL INFO TS=7 FN=26 Rx Pkt UL ASS
 DLGLOBAL INFO UL_TBF_ASS{WAIT_PKT_UL_ASS}: Received Event RX_PKT_UL_ASS
 DLGLOBAL DEBUG Register POLL (TS=7 FN=43, reason=UL_ASS)
-DLGLOBAL INFO UL_TBF_ASS{WAIT_PKT_UL_ASS}: state_chg to SCHED_PKT_CTRL_ACK
-DLGLOBAL DEBUG Rx from lower layers: L1CTL-PDCH_RTS.indication
-DLGLOBAL INFO UL_TBF_ASS{SCHED_PKT_CTRL_ACK}: Received Event CREATE_RLCMAC_MSG
-DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Tx Packet Control Ack
-DLGLOBAL INFO UL_TBF_ASS{SCHED_PKT_CTRL_ACK}: state_chg to COMPLETED
+DLGLOBAL INFO UL_TBF_ASS{WAIT_PKT_UL_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=0xc0
 DLGLOBAL INFO UL_TBF{ASSIGN}: state_chg to FLOW
 DLGLOBAL INFO UL_TBF_ASS{COMPLETED}: state_chg to IDLE
 DLGLOBAL DEBUG Rx from lower layers: L1CTL-PDCH_RTS.indication
+DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Tx Packet Control Ack
+DLGLOBAL DEBUG Rx from lower layers: L1CTL-PDCH_RTS.indication
 DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Sending new block at BSN 0, CS=CS-2
 DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Dequeue next LLC (len=14)
 DLGLOBAL DEBUG -- Chunk with length 14 is less than remaining space (30): add 
length header to delimit LLC frame

--
To view, visit https://gerrit.osmocom.org/c/libosmo-gprs/+/31751
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: libosmo-gprs
Gerrit-Branch: master
Gerrit-Change-Id: Id81f16743f2c464e01caf27ba2eb8c0fc715fe8a
Gerrit-Change-Number: 31751
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to