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

Change subject: rlcmac: dl_tbf: Improve logic requesting a new UL TBF
......................................................................

rlcmac: dl_tbf: Improve logic requesting a new UL TBF

Change-Id: I702872ba32a410bb5f09943af3cdadca482562db
---
M include/osmocom/gprs/rlcmac/gre.h
M include/osmocom/gprs/rlcmac/tbf_ul.h
M include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
M src/rlcmac/gre.c
M src/rlcmac/rlcmac.c
M src/rlcmac/rlcmac_enc.c
M src/rlcmac/sched.c
M src/rlcmac/tbf_ul.c
M src/rlcmac/tbf_ul_ass_fsm.c
M tests/rlcmac/rlcmac_prim_test.c
M tests/rlcmac/rlcmac_prim_test.err
M tests/rlcmac/rlcmac_prim_test.ok
12 files changed, 500 insertions(+), 26 deletions(-)

Approvals:
  pespin: Looks good to me, approved
  Jenkins Builder: Verified




diff --git a/include/osmocom/gprs/rlcmac/gre.h 
b/include/osmocom/gprs/rlcmac/gre.h
index ca5f773..f6397a6 100644
--- a/include/osmocom/gprs/rlcmac/gre.h
+++ b/include/osmocom/gprs/rlcmac/gre.h
@@ -20,6 +20,10 @@
 struct gprs_rlcmac_entity *gprs_rlcmac_entity_alloc(uint32_t tlli);
 void gprs_rlcmac_entity_free(struct gprs_rlcmac_entity *gre);

+bool gprs_rlcmac_entity_in_packet_idle_mode(const struct gprs_rlcmac_entity 
*gre);
+bool gprs_rlcmac_entity_in_packet_transfer_mode(const struct 
gprs_rlcmac_entity *gre);
+bool gprs_rlcmac_entity_have_tx_data_queued(const struct gprs_rlcmac_entity 
*gre);
+
 int gprs_rlcmac_entity_llc_enqueue(struct gprs_rlcmac_entity *gre, uint8_t 
*ll_pdu, unsigned int ll_pdu_len,
                                   enum osmo_gprs_rlcmac_llc_sapi sapi, uint8_t 
radio_prio);

diff --git a/include/osmocom/gprs/rlcmac/tbf_ul.h 
b/include/osmocom/gprs/rlcmac/tbf_ul.h
index 3382778..ab85f50 100644
--- a/include/osmocom/gprs/rlcmac/tbf_ul.h
+++ b/include/osmocom/gprs/rlcmac/tbf_ul.h
@@ -58,6 +58,9 @@

 int gprs_rlcmac_ul_tbf_handle_pkt_ul_ack_nack(struct gprs_rlcmac_ul_tbf 
*ul_tbf,
                                              const RlcMacDownlink_t *dl_block);
+int gprs_rlcmac_ul_tbf_handle_pkt_ul_ass(struct gprs_rlcmac_ul_tbf *ul_tbf,
+                                        const struct osmo_gprs_rlcmac_prim 
*rlcmac_prim,
+                                        const RlcMacDownlink_t *dl_block);

 static inline struct gprs_rlcmac_tbf *ul_tbf_as_tbf(struct gprs_rlcmac_ul_tbf 
*ul_tbf)
 {
diff --git a/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h 
b/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
index 4a1658d..377c86c 100644
--- a/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
+++ b/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h
@@ -32,14 +32,11 @@
                struct gprs_rlcmac_tbf *tbf;
                struct gprs_rlcmac_ul_tbf *ul_tbf;
        };
+       const struct gprs_rlcmac_dl_tbf *dl_tbf; /* Not null if assignment was 
started by a DL TBF ACK/NACK */
        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;
        /* Number of packet resource request transmitted (T3168) */
        unsigned int pkt_res_req_proc_attempts;
 };
@@ -47,9 +44,10 @@
 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_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_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_RX_PKT_UL_ASS, /* (data: struct 
tbf_ul_ass_ev_create_rlcmac_msg_ctx) */
        GPRS_RLCMAC_TBF_UL_ASS_EV_FOOBAR,
 };

@@ -59,6 +57,12 @@
        const IA_RestOctets_t *iaro;
 };

+struct tbf_ul_ass_ev_rx_pkt_ul_ass_ctx {
+       uint8_t ts_nr;
+       uint32_t fn;
+       const RlcMacDownlink_t *dl_block; /* decoded PktUlAss */
+};
+
 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 */
@@ -73,6 +77,8 @@

 int gprs_rlcmac_tbf_ul_ass_start(struct gprs_rlcmac_ul_tbf *ul_tbf, enum 
gprs_rlcmac_tbf_ul_ass_type type);
 int gprs_rlcmac_tbf_ul_ass_start_from_releasing_ul_tbf(struct 
gprs_rlcmac_ul_tbf *ul_tbf, struct gprs_rlcmac_ul_tbf *old_ul_tbf);
+int gprs_rlcmac_tbf_ul_ass_start_from_dl_tbf_ack_nack(struct 
gprs_rlcmac_ul_tbf *ul_tbf, const struct gprs_rlcmac_dl_tbf *dl_tbf);
+
 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);
diff --git a/src/rlcmac/gre.c b/src/rlcmac/gre.c
index 40cd585..53d53c7 100644
--- a/src/rlcmac/gre.c
+++ b/src/rlcmac/gre.c
@@ -66,6 +66,40 @@
        talloc_free(gre);
 }

+/* TS 44.060 5.3 In packet idle mode:
+* - no temporary block flow (TBF) exists..
+* - the mobile station monitors the relevant paging subchannels on CCCH. In 
packet
+* idle mode, upper layers may require the transfer of a upper layer PDU, which
+* implicitly triggers the establishment of a TBF and the transition to packet
+* transfer mode. In packet idle mode, upper layers may require the 
establishment
+* of an RR connection. When the mobile station enters dedicated mode (see 3GPP 
TS
+* 44.018), it may leave the packet idle mode, if the mobile station limitations
+* make it unable to handle the RR connection and the procedures in packet idle
+* mode simultaneously.*/
+bool gprs_rlcmac_entity_in_packet_idle_mode(const struct gprs_rlcmac_entity 
*gre)
+{
+       return !gre->ul_tbf && !gre->dl_tbf;
+}
+
+/* TS 44.060 5.4 "In packet transfer mode, the mobile station is allocated 
radio
+* resources providing one or more TBFs. [...]
+* When a transfer of upper layer PDUs
+* terminates, in either downlink or uplink direction, the corresponding TBF is
+* released. In packet transfer mode, when all TBFs have been released, in 
downlink
+* and uplink direction, the mobile station returns to packet idle mode."
+*/
+bool gprs_rlcmac_entity_in_packet_transfer_mode(const struct 
gprs_rlcmac_entity *gre)
+{
+       return gre->ul_tbf || gre->dl_tbf;
+}
+
+/* Whether MS has data queued from upper layers waiting to be transmitted in 
the
+ * Tx queue (an active UL TBF may still have some extra data) */
+bool gprs_rlcmac_entity_have_tx_data_queued(const struct gprs_rlcmac_entity 
*gre)
+{
+       return gprs_rlcmac_llc_queue_size(gre->llc_queue) > 0;
+}
+
 int gprs_rlcmac_entity_llc_enqueue(struct gprs_rlcmac_entity *gre, uint8_t 
*ll_pdu, unsigned int ll_pdu_len,
                                   enum osmo_gprs_rlcmac_llc_sapi sapi, uint8_t 
radio_prio)
 {
@@ -75,7 +109,11 @@
        if (rc < 0)
                return rc;

-       if (!gre->ul_tbf) {
+       /* TS 44.060 5.3 "In packet idle mode, upper layers may require the
+       * transfer of a upper layer PDU, which implicitly triggers the
+       * establishment of a TBF and the transition to packet transfer mode." */
+       if (gprs_rlcmac_entity_in_packet_idle_mode(gre)) {
+               OSMO_ASSERT(!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)
diff --git a/src/rlcmac/rlcmac.c b/src/rlcmac/rlcmac.c
index 4023586..82394e6 100644
--- a/src/rlcmac/rlcmac.c
+++ b/src/rlcmac/rlcmac.c
@@ -358,6 +358,58 @@
        return rc;
 }

+static int gprs_rlcmac_handle_pkt_ul_ass(const struct osmo_gprs_rlcmac_prim 
*rlcmac_prim, const RlcMacDownlink_t *dl_block)
+{
+       struct gprs_rlcmac_entity *gre = NULL;
+       struct gprs_rlcmac_ul_tbf *ul_tbf = NULL;
+       struct gprs_rlcmac_dl_tbf *dl_tbf;
+       const Packet_Uplink_Assignment_t *ulass = 
&dl_block->u.Packet_Uplink_Assignment;
+       int rc;
+
+       /* Attempt to find relevant UL TBF in assignment state from ID (set 
"gre" ptr): */
+       switch (ulass->ID.UnionType) {
+       case 0: /* GLOBAL_TFI: */
+               switch (ulass->ID.u.Global_TFI.UnionType) {
+               case 0: /* UL TFI */
+                       ul_tbf = 
gprs_rlcmac_find_ul_tbf_by_tfi(ulass->ID.u.Global_TFI.u.UPLINK_TFI);
+                       gre = ul_tbf->tbf.gre;
+                       break;
+               case 1: /* DL TFI */
+                       dl_tbf = 
gprs_rlcmac_find_dl_tbf_by_tfi(ulass->ID.u.Global_TFI.u.DOWNLINK_TFI);
+                       if (dl_tbf)
+                               gre = dl_tbf->tbf.gre;
+                       break;
+               default:
+                       OSMO_ASSERT(0);
+               }
+               break;
+       case 1: /* TLLI */
+               gre = gprs_rlcmac_find_entity_by_tlli(ulass->ID.u.TLLI);
+               if (gre)
+                       ul_tbf = gre->ul_tbf;
+               break;
+       case 2: /* TQI */
+       case 3: /* Packet_Request_Reference */
+               LOGRLCMAC(LOGL_NOTICE, "TS=%u FN=%u Rx Pkt UL ASS: HANDLING OF 
ID=%u NOT IMPLEMENTED!\n",
+                         ulass->ID.UnionType,
+                         rlcmac_prim->l1ctl.pdch_data_ind.ts_nr,
+                         rlcmac_prim->l1ctl.pdch_data_ind.fn);
+               break;
+       }
+
+       if (!gre->ul_tbf) {
+               LOGRLCMAC(LOGL_INFO, "TS=%u FN=%u Rx Pkt UL ACK/NACK: UL_TBF 
TFI=%u not found\n",
+                         rlcmac_prim->l1ctl.pdch_data_ind.ts_nr,
+                         rlcmac_prim->l1ctl.pdch_data_ind.fn,
+                         dl_block->TFI);
+               return -ENOENT;
+       }
+
+       rc = gprs_rlcmac_ul_tbf_handle_pkt_ul_ass(gre->ul_tbf, rlcmac_prim, 
dl_block);
+
+       return rc;
+}
+
 static int gprs_rlcmac_handle_gprs_dl_ctrl_block(const struct 
osmo_gprs_rlcmac_prim *rlcmac_prim)
 {
        struct bitvec *bv;
@@ -388,6 +440,9 @@
        case OSMO_GPRS_RLCMAC_DL_MSGT_PACKET_UPLINK_ACK_NACK:
                rc = gprs_rlcmac_handle_pkt_ul_ack_nack(rlcmac_prim, 
dl_ctrl_block);
                break;
+       case OSMO_GPRS_RLCMAC_DL_MSGT_PACKET_UPLINK_ASSIGNMENT:
+               rc = gprs_rlcmac_handle_pkt_ul_ass(rlcmac_prim, dl_ctrl_block);
+               break;
        default:
                LOGRLCMAC(LOGL_ERROR, "TS=%u FN=%u Rx %s NOT SUPPORTED! 
ignoring\n",
                          rlcmac_prim->l1ctl.pdch_data_ind.ts_nr,
diff --git a/src/rlcmac/rlcmac_enc.c b/src/rlcmac/rlcmac_enc.c
index 6bceb8d..ef1d4cd 100644
--- a/src/rlcmac/rlcmac_enc.c
+++ b/src/rlcmac/rlcmac_enc.c
@@ -386,6 +386,7 @@
 {
        Packet_Downlink_Ack_Nack_t *ack = &block->u.Packet_Downlink_Ack_Nack;
        struct gprs_rlcmac_entity *gre = dl_tbf->tbf.gre;
+       int rc;

        memset(block, 0, sizeof(*block));
        ack->MESSAGE_TYPE = OSMO_GPRS_RLCMAC_UL_MSGT_PACKET_RESOURCE_REQUEST;
@@ -395,8 +396,9 @@
        ack->DOWNLINK_TFI = dl_tbf->cur_alloc.dl_tfi;
        
gprs_rlcmac_enc_prepare_pkt_ack_nack_desc_gprs(&ack->Ack_Nack_Description, 
dl_tbf);

-       /* Channel Request Description */
-       if (gre->ul_tbf && gprs_rlcmac_tbf_ul_ass_pending(gre->ul_tbf)) {
+       /* Channel Request Description. Request a UL-TBF if we have UL data
+        * queued to send and no active UL BF (TS 44.060 8.1.2.5) */
+       if (!gre->ul_tbf && gprs_rlcmac_entity_have_tx_data_queued(gre)) {
                Channel_Request_Description_t *chan_req = 
&ack->Channel_Request_Description;
                ack->Exist_Channel_Request_Description = 1;
                chan_req->PEAK_THROUGHPUT_CLASS = 0; /* TODO */
@@ -404,6 +406,11 @@
                chan_req->RLC_MODE = GPRS_RLCMAC_RLC_MODE_ACKNOWLEDGED;
                chan_req->LLC_PDU_TYPE = GPRS_RLCMAC_LLC_PDU_TYPE_ACKNOWLEDGED;
                chan_req->RLC_OCTET_COUNT = 0; /* TODO */
+
+               gre->ul_tbf = gprs_rlcmac_ul_tbf_alloc(gre);
+               rc = 
gprs_rlcmac_tbf_ul_ass_start_from_dl_tbf_ack_nack(gre->ul_tbf, dl_tbf);
+               if (rc < 0)
+                       LOGPTBFDL(dl_tbf, LOGL_ERROR, "Failed starting 
assignment of requested UL TBF (%d)\n", rc);
        } else {
                ack->Exist_Channel_Request_Description = 0;
        }
diff --git a/src/rlcmac/sched.c b/src/rlcmac/sched.c
index c2b981f..6ec76c7 100644
--- a/src/rlcmac/sched.c
+++ b/src/rlcmac/sched.c
@@ -37,7 +37,8 @@
        struct gprs_rlcmac_dl_tbf *poll_dl_ack; /* 8.1.2.2 7) */
        struct gprs_rlcmac_ul_tbf *poll_ul_ack_new_ul_tbf; /* 9.3.2.4.2  
(answer with PKT RES REQ) */
        struct gprs_rlcmac_ul_tbf *poll_ul_ack; /* 11.2.2 (answer with PKT CTRL 
ACK) */
-       struct gprs_rlcmac_ul_tbf *ul_ass;
+       struct gprs_rlcmac_ul_tbf *poll_ul_ass; /* (answer Pkt UL ASS with PKT 
CTRL ACK) */
+       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)
@@ -80,7 +81,8 @@
        if (node) {
                switch (node->reason) {
                case GPRS_RLCMAC_PDCH_ULC_POLL_UL_ASS:
-                       /* TODO */
+                       /* Answer with ctrl ack generated by 
ul_tbf->ul_ass_fsm. */
+                       tbfs->poll_ul_ass = tbf_as_ul_tbf(node->tbf);
                        break;
                case GPRS_RLCMAC_PDCH_ULC_POLL_DL_ASS:
                        /* TODO */
@@ -207,6 +209,11 @@
                gprs_rlcmac_ul_tbf_free(tbfs->poll_ul_ack);
                return msg;
        }
+       if (tbfs->poll_ul_ass) {
+               msg = 
gprs_rlcmac_tbf_ul_ass_create_rlcmac_msg(tbfs->poll_ul_ass, bi);
+               if (msg)
+                       return msg;
+       }
        if (tbfs->ul_ass) {
                msg = gprs_rlcmac_tbf_ul_ass_create_rlcmac_msg(tbfs->ul_ass, 
bi);
                if (msg)
diff --git a/src/rlcmac/tbf_ul.c b/src/rlcmac/tbf_ul.c
index 7642832..fcd7f56 100644
--- a/src/rlcmac/tbf_ul.c
+++ b/src/rlcmac/tbf_ul.c
@@ -261,6 +261,21 @@
        return rc;
 }

+int gprs_rlcmac_ul_tbf_handle_pkt_ul_ass(struct gprs_rlcmac_ul_tbf *ul_tbf,
+                                        const struct osmo_gprs_rlcmac_prim 
*rlcmac_prim,
+                                        const RlcMacDownlink_t *dl_block)
+{
+       int rc;
+       struct tbf_ul_ass_ev_rx_pkt_ul_ass_ctx d = {
+               .ts_nr = rlcmac_prim->l1ctl.pdch_data_ind.ts_nr,
+               .fn = rlcmac_prim->l1ctl.pdch_data_ind.fn,
+               .dl_block = dl_block,
+       };
+
+       rc = osmo_fsm_inst_dispatch(ul_tbf->ul_ass_fsm.fi, 
GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS, &d);
+       return rc;
+}
+
 struct msgb *gprs_rlcmac_ul_tbf_dummy_create(const struct gprs_rlcmac_ul_tbf 
*ul_tbf)
 {
        struct msgb *msg;
@@ -333,7 +348,7 @@
 bool gprs_rlcmac_ul_tbf_have_data(const struct gprs_rlcmac_ul_tbf *ul_tbf)
 {
        return (ul_tbf->llc_tx_msg && msgb_length(ul_tbf->llc_tx_msg) > 0) ||
-              (gprs_rlcmac_llc_queue_size(ul_tbf->tbf.gre->llc_queue) > 0);
+              gprs_rlcmac_entity_have_tx_data_queued(ul_tbf->tbf.gre);
 }

 bool gprs_rlcmac_ul_tbf_shall_keep_open(const struct gprs_rlcmac_ul_tbf 
*ul_tbf, const struct gprs_rlcmac_rts_block_ind *bi)
diff --git a/src/rlcmac/tbf_ul_ass_fsm.c b/src/rlcmac/tbf_ul_ass_fsm.c
index 6169080..d88acd3 100644
--- a/src/rlcmac/tbf_ul_ass_fsm.c
+++ b/src/rlcmac/tbf_ul_ass_fsm.c
@@ -32,12 +32,14 @@
 #include <osmocom/gprs/rlcmac/sched.h>
 #include <osmocom/gprs/rlcmac/csn1_defs.h>
 #include <osmocom/gprs/rlcmac/rlcmac_enc.h>
+#include <osmocom/gprs/rlcmac/pdch_ul_controller.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_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_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" },
@@ -165,14 +167,73 @@
        return -EFAULT;
 }

+static int handle_pkt_ul_ass(struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx, const 
struct tbf_ul_ass_ev_rx_pkt_ul_ass_ctx *d)
+{
+
+       const Packet_Uplink_Assignment_t *ulass = 
&d->dl_block->u.Packet_Uplink_Assignment;
+       uint8_t tn;
+       const Timeslot_Allocation_t *ts_alloc;
+       const Timeslot_Allocation_Power_Ctrl_Param_t *ts_alloc_pwr_ctl;
+
+       switch (ulass->UnionType) {
+       case 0: /* ulass->u.PUA_GPRS_Struct.* (PUA_GPRS_t) */
+               ctx->ul_tbf->tx_cs = 
ulass->u.PUA_GPRS_Struct.CHANNEL_CODING_COMMAND + 1;
+               switch (ulass->u.PUA_GPRS_Struct.UnionType) {
+               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 */
+                       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];
+                               ctx->phase2_alloc.num_ts = 0;
+                               for (tn = 0; tn < 8; tn++) {
+                                       ctx->phase2_alloc.ts[tn].allocated = 
ts_alloc[tn].Exist;
+                                       if (ts_alloc[tn].Exist) {
+                                               ctx->phase2_alloc.num_ts++;
+                                               ctx->phase2_alloc.ts[tn].usf = 
ts_alloc[tn].USF_TN;
+                                       }
+                               }
+                               break;
+                       case 1: /* Timeslot_Allocation_Power_Ctrl_Param_t */
+                               /* TODO: ALPHA, GAMMA */
+                               ts_alloc_pwr_ctl = 
&ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.u.Timeslot_Allocation_Power_Ctrl_Param;
+                               ctx->phase2_alloc.num_ts = 0;
+                               for (tn = 0; tn < 8; tn++) {
+                                       ctx->phase2_alloc.ts[tn].allocated = 
ts_alloc_pwr_ctl->Slot[tn].Exist;
+                                       if (ts_alloc_pwr_ctl->Slot[tn].Exist) {
+                                               ctx->phase2_alloc.num_ts++;
+                                               ctx->phase2_alloc.ts[tn].usf = 
ts_alloc_pwr_ctl->Slot[tn].USF_TN;
+                                       }
+                               }
+                               break;
+                       }
+                       break;
+               case 2: /* Single Block Allocation */
+                       LOGPFSML(ctx->fi, LOGL_NOTICE, "Rx Pkt Ul Ass GPRS 
Single Block Allocation not supported!\n");
+                       return -ENOTSUP;
+               case 0: /* Fixed Allocation */
+                       LOGPFSML(ctx->fi, LOGL_NOTICE, "Rx Pkt Ul Ass GPRS 
Fixed Allocation not supported!\n");
+                       return -ENOTSUP;
+               }
+               return 0;
+       case 1: /* ulass->u.PUA_EGPRS_Struct.* (PUA_EGPRS_t) */
+               LOGPFSML(ctx->fi, LOGL_NOTICE, "Rx Pkt Ul Ass EGPRS not 
supported!\n");
+               return -ENOTSUP;
+       }
+
+       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: */
+       ctx->dl_tbf = NULL;
        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)
@@ -191,6 +252,11 @@
                ctx->ass_type = GPRS_RLCMAC_TBF_UL_ASS_TYPE_2PHASE;
                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_START_FROM_DL_TBF:
+               osmo_fsm_inst_dispatch(ctx->ul_tbf->state_fsm.fi, 
GPRS_RLCMAC_TBF_UL_EV_UL_ASS_START, NULL);
+               ctx->ass_type = GPRS_RLCMAC_TBF_UL_ASS_TYPE_2PHASE;
+               tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_PKT_UL_ASS);
+               break;
        default:
                OSMO_ASSERT(0);
        }
@@ -235,12 +301,27 @@

 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;
+       struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct 
gprs_rlcmac_tbf_ul_ass_fsm_ctx *)fi->priv;
+       struct tbf_ul_ass_ev_rx_pkt_ul_ass_ctx *d;
+       int rc;
+
        switch (event) {
        case GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS:
-               // TODO: fill ctx->phase2_alloc with contents from 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.
-               tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK);
+               /* 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));
+                       tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK);
+               } else {
+                       tbf_ul_ass_fsm_state_chg(fi, 
GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL);
+               }
                break;
        default:
                OSMO_ASSERT(0);
@@ -249,15 +330,13 @@

 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 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;
+               data_ctx->msg = 
gprs_rlcmac_ul_tbf_create_pkt_ctrl_ack(ctx->ul_tbf);
                if (!data_ctx->msg)
                        return;
                tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL);
@@ -275,7 +354,7 @@
        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));
+               memcpy(&ctx->ul_tbf->cur_alloc, &ctx->phase2_alloc, 
sizeof(ctx->phase2_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. */
@@ -286,10 +365,12 @@
        [GPRS_RLCMAC_TBF_UL_ASS_ST_IDLE] = {
                .in_event_mask =
                        X(GPRS_RLCMAC_TBF_UL_ASS_EV_START) |
-                       X(GPRS_RLCMAC_TBF_UL_ASS_EV_START_DIRECT_2PHASE),
+                       X(GPRS_RLCMAC_TBF_UL_ASS_EV_START_DIRECT_2PHASE) |
+                       X(GPRS_RLCMAC_TBF_UL_ASS_EV_START_FROM_DL_TBF),
                .out_state_mask =
                        X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_CCCH_IMM_ASS) |
-                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ),
+                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ) |
+                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_PKT_UL_ASS),
                .name = "IDLE",
                .onenter = st_idle_on_enter,
                .action = st_idle,
@@ -316,7 +397,8 @@
                        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_SCHED_PKT_CTRL_ACK) |
+                       X(GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL),
                .name = "WAIT_PKT_UL_ASS",
                .action = st_wait_pkt_ul_ass,
        },
@@ -343,6 +425,17 @@
        struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct 
gprs_rlcmac_tbf_ul_ass_fsm_ctx *)fi->priv;
        switch (fi->T) {
        case 3168:
+               /* If the UL TBF assignment was started from DL TBF it is not
+               really possible reattempting because we haven't yet any phase1
+               allocation. Hence simply destroy the TBF and let next DL TBF DL
+               ACK/NACK re-request an UL TBF assignment: */
+               if (ctx->dl_tbf) {
+                       LOGPFSML(ctx->fi, LOGL_NOTICE,
+                                "UL TBF establishment failure (T3168 timeout 
attempts=%u, ass from DL TBF)\n",
+                                ctx->pkt_res_req_proc_attempts);
+                       gprs_rlcmac_ul_tbf_free(ctx->ul_tbf);
+                       return 0;
+               }
                /* TS 44.060 7.1.3.3: "the mobile station shall then reinitiate 
the packet access
                 * procedure unless the packet access procedure has already 
been attempted four
                 * times. In that case, TBF failure has occurred and an RLC/MAC 
error should be
@@ -424,6 +517,18 @@
        return rc;
 }

+/* A DL-TBF requested a UL TBF over DL ACK/NACK, wait to receive Pkt Ul Ass for
+ * it, aka switch the FSM to trigger the 2hpase directly (tx Pkt Res Req) */
+int gprs_rlcmac_tbf_ul_ass_start_from_dl_tbf_ack_nack(struct 
gprs_rlcmac_ul_tbf *ul_tbf, const struct gprs_rlcmac_dl_tbf *dl_tbf)
+{
+       int rc;
+       ul_tbf->ul_ass_fsm.dl_tbf = dl_tbf;
+       rc = osmo_fsm_inst_dispatch(ul_tbf->ul_ass_fsm.fi,
+                                   GPRS_RLCMAC_TBF_UL_ASS_EV_START_FROM_DL_TBF,
+                                   NULL);
+       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;
@@ -449,9 +554,6 @@
        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;
        };
diff --git a/tests/rlcmac/rlcmac_prim_test.c b/tests/rlcmac/rlcmac_prim_test.c
index 02ee04c..604546d 100644
--- a/tests/rlcmac/rlcmac_prim_test.c
+++ b/tests/rlcmac/rlcmac_prim_test.c
@@ -295,6 +295,75 @@
                
ack_desc->RECEIVED_BLOCK_BITMAP[sizeof(ack_desc->RECEIVED_BLOCK_BITMAP) - idx/8 
- 1] &= ~(1 << (idx & 0x03));
 }

+static void pkt_ul_ass_from_dl_tbf_init(RlcMacDownlink_t *block, uint8_t 
dl_tfi, uint8_t new_ul_tfi, uint16_t arfcn, uint8_t *usf_li)
+{
+       Packet_Uplink_Assignment_t *pua = &block->u.Packet_Uplink_Assignment;
+       PUA_GPRS_t *gprs = &pua->u.PUA_GPRS_Struct;
+       Packet_Timing_Advance_t *pta = &gprs->Packet_Timing_Advance;
+       Frequency_Parameters_t *fp = &gprs->Frequency_Parameters;
+       Dynamic_Allocation_t *da = &gprs->u.Dynamic_Allocation;
+       unsigned int tn;
+
+       memset(block, 0, sizeof(*block));
+       block->PAYLOAD_TYPE = GPRS_RLCMAC_PT_CONTROL_BLOCK;
+       block->RRBP = 0;
+       block->SP = 0;
+       block->USF = 0x00;
+       block->u.MESSAGE_TYPE = 
OSMO_GPRS_RLCMAC_DL_MSGT_PACKET_UPLINK_ASSIGNMENT;
+
+       /* See 3GPP TS 44.060, section 11.2.29 */
+       pua = &block->u.Packet_Uplink_Assignment;
+       pua->MESSAGE_TYPE = OSMO_GPRS_RLCMAC_DL_MSGT_PACKET_UPLINK_ASSIGNMENT;
+       pua->PAGE_MODE    = 0x00;
+
+       /* TLLI or Global DL TFI */
+       pua->ID.UnionType = 0x00;
+       pua->ID.u.Global_TFI.UnionType = 0x01;
+       pua->ID.u.Global_TFI.u.UPLINK_TFI = dl_tfi;
+
+       /* GPRS specific parameters */
+       pua->UnionType = 0x00;
+       /* Use the commanded CS/MCS value during the content resolution */
+       gprs->CHANNEL_CODING_COMMAND    = 
gprs_rlcmac_mcs_chan_code(GPRS_RLCMAC_MCS_2);
+       gprs->TLLI_BLOCK_CHANNEL_CODING = 0x01;  // ^^^
+       /* Dynamic allocation */
+       gprs->UnionType = 0x01;
+       /* Frequency Parameters IE is present */
+       gprs->Exist_Frequency_Parameters = 0x01;
+
+       /* Packet Timing Advance (if known) */
+       pta->Exist_TIMING_ADVANCE_VALUE = 0x01;  // Present
+       pta->TIMING_ADVANCE_VALUE       = 1;
+
+       /* Continuous Timing Advance Control */
+       pta->Exist_IndexAndtimeSlot         = 0x01;  // Present
+       pta->TIMING_ADVANCE_TIMESLOT_NUMBER = 0;  // FIXME!
+       pta->TIMING_ADVANCE_INDEX           = 2;
+
+       /* Frequency Parameters IE */
+       fp->TSC = 2;
+       fp->UnionType = 0x00;
+       fp->u.ARFCN = arfcn;
+
+       /* Dynamic allocation parameters */
+       da->USF_GRANULARITY = 0x00;
+
+       /* Assign an Uplink TFI */
+       da->Exist_UPLINK_TFI_ASSIGNMENT = 0x01;
+       da->UPLINK_TFI_ASSIGNMENT = new_ul_tfi;
+
+       /* Timeslot Allocation with or without Power Control */
+       da->UnionType = 0x00;
+
+       for (tn = 0; tn < 8; tn++) {
+               Timeslot_Allocation_t *slot = &da->u.Timeslot_Allocation[tn];
+               if (usf_li[tn] == 0xff)
+                       continue;
+               slot->Exist  = 0x01;  // Enable this timeslot
+               slot->USF_TN = usf_li[tn];  // USF_TN(i)
+       }
+}
+
 static uint8_t *create_si13(uint8_t bs_cv_max /* 0..15 */)
 {
        static uint8_t si13_buf[GSM_MACBLOCK_LEN];
@@ -869,6 +938,88 @@
        cleanup_test();
 }

+/* PCU allocates a DL TBF through PCH ImmAss for MS (when in packet-idle). Then
+ * upper layers want to transmit more data so during DL ACK/NACK a new UL TBF 
is
+ * requested. */
+static void test_dl_tbf_ccch_assign_requests_ul_tbf_pacch(void)
+{
+       struct osmo_gprs_rlcmac_prim *rlcmac_prim;
+       int rc;
+       struct msgb *dl_data_msg;
+
+       printf("=== %s start ===\n", __func__);
+       prepare_test();
+       RlcMacDownlink_t dl_block;
+       uint32_t tlli = 0x0000001;
+       uint8_t ts_nr = 7;
+       uint8_t usf = 0;
+       uint32_t rts_fn = 4;
+       uint8_t dl_tfi = 0;
+       uint8_t ul_tfi = 3;
+       uint8_t rrbp = GPRS_RLCMAC_RRBP_N_plus_17_18;
+       uint16_t arfcn = 871;
+       uint8_t usf_li[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1, 2 };
+
+       /* Notify RLCMAC about our TLLI */
+       rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_gmmrr_assign_req(tlli);
+       rc = osmo_gprs_rlcmac_prim_upper_down(rlcmac_prim);
+
+       OSMO_ASSERT(sizeof(ccch_imm_ass_pkt_dl_tbf) == GSM_MACBLOCK_LEN);
+       rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_ccch_data_ind(0, 
ccch_imm_ass_pkt_dl_tbf);
+       rc = osmo_gprs_rlcmac_prim_lower_up(rlcmac_prim);
+       OSMO_ASSERT(rc == 0);
+
+       /* Transmit some DL LLC data MS<-PCU */
+       dl_data_msg = create_dl_data_block(dl_tfi, usf, GPRS_RLCMAC_CS_1, 0, 
true, true, rrbp);
+       rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_pdch_data_ind(ts_nr, 
rts_fn, 0, 0, 0,
+                                                                     
msgb_data(dl_data_msg),
+                                                                     
msgb_length(dl_data_msg));
+       rc = osmo_gprs_rlcmac_prim_lower_up(rlcmac_prim);
+       OSMO_ASSERT(rc == 0);
+       msgb_free(dl_data_msg);
+
+       /* Upper layers wants to transmit some payload, but no UL TBF exists 
yet: */
+       /* Submit 14 bytes to fit in 1 RLCMAC block to shorten test and end up 
in FINISHED state quickly: */
+       rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_grr_unitdata_req(tlli, 
pdu_llc_gmm_att_req, 14);
+       rlcmac_prim->grr.unitdata_req.sapi = OSMO_GPRS_RLCMAC_LLC_SAPI_GMM;
+       rc = osmo_gprs_rlcmac_prim_upper_down(rlcmac_prim);
+       OSMO_ASSERT(rc == 0);
+
+       /* Trigger transmission of DL ACK/NACK, which should request a UL TBF 
in "Channel Request Description" */
+       rts_fn = rrbp2fn(rts_fn, rrbp);
+       rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_pdch_rts_ind(ts_nr, 
rts_fn, usf);
+       rc = osmo_gprs_rlcmac_prim_lower_up(rlcmac_prim);
+       OSMO_ASSERT(rc == 0);
+
+       /* Network sends a Pkt Ul Ass to DL TBF's PACCH: */
+       rts_fn = fn_next_block(rts_fn);
+       pkt_ul_ass_from_dl_tbf_init(&dl_block, dl_tfi, ul_tfi, arfcn, 
&usf_li[0]);
+       /* has Poll set: */
+       dl_block.SP = 1;
+       dl_block.RRBP = rrbp;
+       rlcmac_prim = create_dl_ctrl_block(&dl_block, ts_nr, rts_fn);
+       rc = osmo_gprs_rlcmac_prim_lower_up(rlcmac_prim);
+       OSMO_ASSERT(rc == 0);
+
+       /* Trigger transmission of PKT CTRL ACK */
+       rts_fn = rrbp2fn(rts_fn, rrbp);
+       rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_pdch_rts_ind(ts_nr, 
rts_fn, usf_li[ts_nr]);
+       rc = osmo_gprs_rlcmac_prim_lower_up(rlcmac_prim);
+       OSMO_ASSERT(rc == 0);
+
+       /* from now on use one of the assigned TS in UL TBF.*/
+       rts_fn = fn_next_block(rts_fn);
+       ts_nr = 6;
+
+       /* Trigger transmission of LLC data (GMM Attach) (first part) */
+       rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_pdch_rts_ind(ts_nr, 
rts_fn, usf_li[ts_nr]);
+       rc = osmo_gprs_rlcmac_prim_lower_up(rlcmac_prim);
+       OSMO_ASSERT(rc == 0);
+
+       printf("=== %s end ===\n", __func__);
+       cleanup_test();
+}
+
 static const struct log_info_cat test_log_categories[] = { };
 static const struct log_info test_log_info = {
        .cat = test_log_categories,
@@ -899,6 +1050,7 @@
        test_ul_tbf_last_data_cv0_retrans_max();
        test_ul_tbf_request_another_ul_tbf();
        test_dl_tbf_ccch_assign();
+       test_dl_tbf_ccch_assign_requests_ul_tbf_pacch();

        talloc_free(tall_ctx);
 }
diff --git a/tests/rlcmac/rlcmac_prim_test.err 
b/tests/rlcmac/rlcmac_prim_test.err
index c022e4a..6ffd87d 100644
--- a/tests/rlcmac/rlcmac_prim_test.err
+++ b/tests/rlcmac/rlcmac_prim_test.err
@@ -620,3 +620,70 @@
 DLGLOBAL DEBUG (ts=7,fn=21,usf=0) Tx DL ACK/NACK FinalAck=1
 DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) - V(N): 
"IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIR" R=Received 
I=Invalid
 DLGLOBAL INFO DL_TBF{FINISHED}: Deallocated
+DLGLOBAL INFO Rx from upper layers: GMMRR-ASSIGN.request
+DLGLOBAL INFO GMMRR-ASSIGN.req: creating new entity TLLI=0x00000001
+DLGLOBAL INFO Rx from lower layers: L1CTL-CCCH_DATA.indication
+DLGLOBAL INFO GRE(00000001) Got PCH IMM_ASS (DL_TBF): DL_TFI=0 TS=7
+DLGLOBAL INFO DL_TBF{NEW}: Allocated
+DLGLOBAL INFO DL_TBF{NEW}: Received Event DL_ASS_COMPL
+DLGLOBAL INFO TBF(DL:NR-0:TLLI-00000001) Send L1CTL-CF_DL_TBF.req 
dl_slotmask=0x80 dl_tfi=0
+DLGLOBAL INFO DL_TBF{NEW}: state_chg to FLOW
+DLGLOBAL INFO Rx from lower layers: L1CTL-PDCH_DATA.indication
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) Rx new DL data
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) DL DATA TFI=0 received (V(Q)=0 .. 
V(R)=0)
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) Got CS-1 RLC data block: FBI=1, 
BSN=0, SPB=0, S/P=1 RRBP=1, E=0, bitoffs=24
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) BSN 0 storing in window (0..63)
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) data_length=20, data=19 43 c0 01 2b 
2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
+DLGLOBAL DEBUG - Raising V(R) to 1
+DLGLOBAL DEBUG - Taking block 0 out, raising V(Q) to 1
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) Assembling frames: (len=20)
+DLGLOBAL DEBUG DL DATA LI contains extension octet: LI=6, M=0, E=1, count=0
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) Frame 1 starts at offset 1, 
length=6, is_complete=1
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) complete UL frame len=6
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) No gaps in received block, last 
block: BSN=0 FBI=1
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) Finished with DL TBF
+DLGLOBAL INFO DL_TBF{FLOW}: Received Event LAST_DL_DATA_RECVD
+DLGLOBAL INFO DL_TBF{FLOW}: state_chg to FINISHED
+DLGLOBAL DEBUG Register POLL (TS=7 FN=21, reason=DL_ACK)
+DLGLOBAL INFO Rx from upper layers: GRR-UNITDATA.request
+DLGLOBAL INFO Rx from lower layers: L1CTL-PDCH_RTS.indication
+DLGLOBAL DEBUG (ts=7,fn=21,usf=0) Tx DL ACK/NACK FinalAck=1
+DLGLOBAL DEBUG TBF(DL:NR-0:TLLI-00000001) - V(N): 
"IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIR" R=Received 
I=Invalid
+DLGLOBAL INFO UL_TBF{NEW}: Allocated
+DLGLOBAL INFO UL_TBF_ASS{IDLE}: Allocated
+DLGLOBAL INFO UL_TBF_ASS{IDLE}: Received Event START_FROM_DL_TBF
+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}: state_chg to WAIT_PKT_UL_ASS
+DLGLOBAL INFO Rx from lower layers: L1CTL-PDCH_DATA.indication
+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 INFO 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{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 INFO 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
+DLGLOBAL DEBUG -- Final block, so we done.
+DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Complete UL frame, len=0
+DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) data block (BSN 0, CS-2): 39 01 c0 
00 08 01 01 d5 71 00 00 08 29 26 24 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
+DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) need_padding 0 spb_status 0 spb 0 
(BSN1 0 BSN2 -1)
+DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Copying 1 RLC blocks, 1 BSNs
+DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Copying data unit 0 (BSN 0)
+DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) msg block (BSN 0, CS-2): 00 06 00 39 
01 c0 00 08 01 01 d5 71 00 00 08 29 26 24 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
2b 2b 2b 00
+DLGLOBAL INFO UL_TBF{FLOW}: Received Event FIRST_UL_DATA_SENT
+DLGLOBAL INFO UL_TBF{FLOW}: First UL block sent, stop T3164
+DLGLOBAL INFO UL_TBF{FLOW}: Received Event LAST_UL_DATA_SENT
+DLGLOBAL INFO UL_TBF{FLOW}: Last UL block sent (CV=0), start T3182
+DLGLOBAL INFO UL_TBF{FLOW}: state_chg to FINISHED
+DLGLOBAL INFO DL_TBF{FINISHED}: Deallocated
+DLGLOBAL INFO UL_TBF_ASS{IDLE}: Deallocated
+DLGLOBAL INFO UL_TBF{FINISHED}: Deallocated
diff --git a/tests/rlcmac/rlcmac_prim_test.ok b/tests/rlcmac/rlcmac_prim_test.ok
index d2bce62..7bafb85 100644
--- a/tests/rlcmac/rlcmac_prim_test.ok
+++ b/tests/rlcmac/rlcmac_prim_test.ok
@@ -117,3 +117,12 @@
 test_rlcmac_prim_up_cb(): Rx GRR-UNITDATA.indication TLLI=0x00000001 ll=[43 c0 
01 2b 2b 2b ]
 test_rlcmac_prim_down_cb(): Rx L1CTL-PDCH_DATA.request fn=21 ts=7 data_len=23 
data=[40 14 00 00 00 00 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b ]
 === test_dl_tbf_ccch_assign end ===
+=== test_dl_tbf_ccch_assign_requests_ul_tbf_pacch start ===
+sys={0.000000}, mono={0.000000}: clock_override_set
+test_rlcmac_prim_down_cb(): Rx L1CTL-CFG_DL_TBF.request dl_tbf_nr=0 
dl_slotmask=0x80 dl_tfi=0
+test_rlcmac_prim_up_cb(): Rx GRR-UNITDATA.indication TLLI=0x00000001 ll=[43 c0 
01 2b 2b 2b ]
+test_rlcmac_prim_down_cb(): Rx L1CTL-PDCH_DATA.request fn=21 ts=7 data_len=23 
data=[40 14 00 00 00 00 00 00 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b ]
+test_rlcmac_prim_down_cb(): Rx L1CTL-CFG_UL_TBF.request ul_tbf_nr=0 
ul_slotmask=0xc0
+test_rlcmac_prim_down_cb(): Rx L1CTL-PDCH_DATA.request fn=43 ts=7 data_len=23 
data=[40 04 00 00 00 04 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b ]
+test_rlcmac_prim_down_cb(): Rx L1CTL-PDCH_DATA.request fn=47 ts=6 data_len=34 
data=[00 06 00 39 01 c0 00 08 01 01 d5 71 00 00 08 29 26 24 2b 2b 2b 2b 2b 2b 
2b 2b 2b 2b 2b 2b 2b 2b 2b 00 ]
+=== test_dl_tbf_ccch_assign_requests_ul_tbf_pacch end ===

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

Gerrit-Project: libosmo-gprs
Gerrit-Branch: master
Gerrit-Change-Id: I702872ba32a410bb5f09943af3cdadca482562db
Gerrit-Change-Number: 31576
Gerrit-PatchSet: 3
Gerrit-Owner: pespin <pes...@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <lafo...@osmocom.org>
Gerrit-Reviewer: pespin <pes...@sysmocom.de>
Gerrit-MessageType: merged

Reply via email to