pespin has submitted this change. (
https://gerrit.osmocom.org/c/libosmo-gprs/+/31325 )
Change subject: rlcmac: Introduce initial poll answer infrastructure
......................................................................
rlcmac: Introduce initial poll answer infrastructure
This commit imports pdch_ul_controller.{c,h} from osmo-pcu.git
d8cea3c618dbd2a343e6c012e5545006d44fc244 and adapts it to be of use on
the MS side.
Related: OS#5500
Change-Id: I9d38a8de4240e65585cc8bbe3c044473af5a83e5
---
M include/osmocom/gprs/rlcmac/Makefile.am
A include/osmocom/gprs/rlcmac/pdch_ul_controller.h
M include/osmocom/gprs/rlcmac/rlcmac_private.h
M include/osmocom/gprs/rlcmac/sched.h
M include/osmocom/gprs/rlcmac/tbf_dl.h
M include/osmocom/gprs/rlcmac/types_private.h
M src/rlcmac/Makefile.am
A src/rlcmac/pdch_ul_controller.c
M src/rlcmac/rlcmac.c
M src/rlcmac/sched.c
M src/rlcmac/tbf_dl.c
M tests/rlcmac/rlcmac_prim_test.c
M tests/rlcmac/rlcmac_prim_test.err
13 files changed, 439 insertions(+), 14 deletions(-)
Approvals:
laforge: Looks good to me, but someone else must approve
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 7a95174..81cfecd 100644
--- a/include/osmocom/gprs/rlcmac/Makefile.am
+++ b/include/osmocom/gprs/rlcmac/Makefile.am
@@ -3,6 +3,7 @@
coding_scheme.h \
gre.h \
llc_queue.h \
+ pdch_ul_controller.h \
rlc.h \
rlc_window.h \
rlc_window_dl.h \
diff --git a/include/osmocom/gprs/rlcmac/pdch_ul_controller.h
b/include/osmocom/gprs/rlcmac/pdch_ul_controller.h
new file mode 100644
index 0000000..52970c4
--- /dev/null
+++ b/include/osmocom/gprs/rlcmac/pdch_ul_controller.h
@@ -0,0 +1,60 @@
+/* pdch_ul_controller.h
+ *
+ * Copyright (C) 2021-2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin(a)sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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 General Public License for more details.
+ */
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <osmocom/core/linuxrbtree.h>
+#include <osmocom/core/utils.h>
+
+struct gprs_rlcmac_dl_tbf;
+
+struct gprs_rlcmac_pdch_ulc {
+ uint8_t ts_nr;
+ struct rb_root tree_root;
+ void *pool_ctx; /* talloc pool of struct pdch_ulc_node */
+};
+
+
+enum gprs_rlcmac_pdch_ulc_poll_reason {
+ GPRS_RLCMAC_PDCH_ULC_POLL_UL_ASS, /* Tx CTRL ACK for received UL ASS */
+ GPRS_RLCMAC_PDCH_ULC_POLL_DL_ASS, /* Tx CTRL ACK for received DL ASS */
+ GPRS_RLCMAC_PDCH_ULC_POLL_UL_ACK, /* Tx CTRL ACK (or PKT RES REQ on final UL ACK/NACK)
for received UL ACK/NACK */
+ GPRS_RLCMAC_PDCH_ULC_POLL_DL_ACK, /* Tx DL ACK/NACK (or others 8.1.2.2) for received
data block */
+ GPRS_RLCMAC_PDCH_ULC_POLL_CELL_CHG_CONTINUE, /* Tx CTRL ACK for received Pkt cell Change
Continue */
+};
+extern const struct value_string gprs_rlcmac_pdch_ulc_poll_reason_names[];
+
+struct gprs_rlcmac_pdch_ulc_node {
+ struct rb_node node; /*! entry in gprs_rlcmac_pdch_ulc->tree_root */
+ uint32_t fn;
+ enum gprs_rlcmac_pdch_ulc_poll_reason reason;
+ struct gprs_rlcmac_tbf *tbf;
+};
+
+struct gprs_rlcmac_pdch_ulc *gprs_rlcmac_pdch_ulc_alloc(void *ctx, uint8_t ts_nr);
+
+int gprs_rlcmac_pdch_ulc_reserve(struct gprs_rlcmac_pdch_ulc *ulc, uint32_t fn, enum
gprs_rlcmac_pdch_ulc_poll_reason reason, struct gprs_rlcmac_tbf *tbf);
+
+struct gprs_rlcmac_pdch_ulc_node *gprs_rlcmac_pdch_ulc_get_node(struct
gprs_rlcmac_pdch_ulc *ulc, uint32_t fn);
+struct gprs_rlcmac_pdch_ulc_node *gprs_rlcmac_pdch_ulc_pop_node(struct
gprs_rlcmac_pdch_ulc *ulc, uint32_t fn);
+
+void gprs_rlcmac_pdch_ulc_release_node(struct gprs_rlcmac_pdch_ulc *ulc, struct
gprs_rlcmac_pdch_ulc_node *item);
+void gprs_rlcmac_pdch_ulc_release_tbf(struct gprs_rlcmac_pdch_ulc *ulc, const struct
gprs_rlcmac_tbf *tbf);
+int gprs_rlcmac_pdch_ulc_release_fn(struct gprs_rlcmac_pdch_ulc *ulc, uint32_t fn);
+
+void gprs_rlcmac_pdch_ulc_expire_fn(struct gprs_rlcmac_pdch_ulc *ulc, uint32_t fn);
diff --git a/include/osmocom/gprs/rlcmac/rlcmac_private.h
b/include/osmocom/gprs/rlcmac/rlcmac_private.h
index fc65753..f5bbfb0 100644
--- a/include/osmocom/gprs/rlcmac/rlcmac_private.h
+++ b/include/osmocom/gprs/rlcmac/rlcmac_private.h
@@ -69,6 +69,10 @@
uint8_t next_ul_tbf_nr;
uint8_t next_dl_tbf_nr;
+
+ struct {
+ struct gprs_rlcmac_pdch_ulc *ulc[8];
+ } sched;
};
extern struct gprs_rlcmac_ctx *g_ctx;
diff --git a/include/osmocom/gprs/rlcmac/sched.h b/include/osmocom/gprs/rlcmac/sched.h
index d344aea..c7fa82a 100644
--- a/include/osmocom/gprs/rlcmac/sched.h
+++ b/include/osmocom/gprs/rlcmac/sched.h
@@ -9,4 +9,6 @@
uint8_t usf;
};
+uint32_t rrbp2fn(uint32_t cur_fn, uint8_t rrbp);
+
int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_rts_block_ind *bi);
diff --git a/include/osmocom/gprs/rlcmac/tbf_dl.h b/include/osmocom/gprs/rlcmac/tbf_dl.h
index 5d7941d..facae81 100644
--- a/include/osmocom/gprs/rlcmac/tbf_dl.h
+++ b/include/osmocom/gprs/rlcmac/tbf_dl.h
@@ -42,7 +42,7 @@
int gprs_rlcmac_dl_tbf_rcv_data_block(struct gprs_rlcmac_dl_tbf *dl_tbf,
const struct gprs_rlcmac_rlc_data_info *rlc,
- uint8_t *data);
+ uint8_t *data, uint32_t fn, uint8_t ts_nr);
static inline struct gprs_rlcmac_tbf *dl_tbf_as_tbf(struct gprs_rlcmac_dl_tbf *dl_tbf)
{
diff --git a/include/osmocom/gprs/rlcmac/types_private.h
b/include/osmocom/gprs/rlcmac/types_private.h
index 8450d08..77a0504 100644
--- a/include/osmocom/gprs/rlcmac/types_private.h
+++ b/include/osmocom/gprs/rlcmac/types_private.h
@@ -3,6 +3,14 @@
#include <osmocom/gprs/rlcmac/types.h>
+/* TS 44.060 able 10.4.5.1 RRBP offsets */
+enum gprs_rlcmac_rrbp_field {
+ GPRS_RLCMAC_RRBP_N_plus_13 = 0x0,
+ GPRS_RLCMAC_RRBP_N_plus_17_18 = 0x1,
+ GPRS_RLCMAC_RRBP_N_plus_21_22 = 0x2,
+ GPRS_RLCMAC_RRBP_N_plus_26 = 0x3,
+};
+
/* TS 44.060 Section 10.4.7 Table 10.4.7.1: Payload Type field */
enum gprs_rlcmac_payload_type {
GPRS_RLCMAC_PT_DATA_BLOCK = 0x0,
diff --git a/src/rlcmac/Makefile.am b/src/rlcmac/Makefile.am
index 68ab832..9133df0 100644
--- a/src/rlcmac/Makefile.am
+++ b/src/rlcmac/Makefile.am
@@ -30,6 +30,7 @@
csn1_ts_44_018.c \
csn1_ts_44_060.c \
gre.c \
+ pdch_ul_controller.c \
llc_queue.c \
rlc_window.c \
rlc_window_dl.c \
diff --git a/src/rlcmac/pdch_ul_controller.c b/src/rlcmac/pdch_ul_controller.c
new file mode 100644
index 0000000..7a3b753
--- /dev/null
+++ b/src/rlcmac/pdch_ul_controller.c
@@ -0,0 +1,212 @@
+/* pdch_ul_controller.c
+ *
+ * Copyright (C) 2021-2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin(a)sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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 General Public License for more details.
+ */
+
+#include <inttypes.h>
+#include <unistd.h>
+#include <talloc.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/linuxrbtree.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <osmocom/gprs/rlcmac/pdch_ul_controller.h>
+#include <osmocom/gprs/rlcmac/rlcmac_private.h>
+#include <osmocom/gprs/rlcmac/types_private.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)
+
+const struct value_string gprs_rlcmac_pdch_ulc_poll_reason_names[] = {
+ { GPRS_RLCMAC_PDCH_ULC_POLL_UL_ASS, "UL_ASS" },
+ { GPRS_RLCMAC_PDCH_ULC_POLL_DL_ASS, "DL_ASS" },
+ { GPRS_RLCMAC_PDCH_ULC_POLL_UL_ACK, "UL_ACK" },
+ { GPRS_RLCMAC_PDCH_ULC_POLL_DL_ACK, "DL_ACK" },
+ { GPRS_RLCMAC_PDCH_ULC_POLL_CELL_CHG_CONTINUE, "CELL_CHG_CONTINUE" },
+ { 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;
+ ulc = talloc_zero(ctx, struct gprs_rlcmac_pdch_ulc);
+ if (!ulc)
+ return ulc;
+
+ ulc->ts_nr = ts_nr;
+ ulc->pool_ctx = talloc_pool(ulc, sizeof(struct gprs_rlcmac_pdch_ulc_node) *
MAX_FN_RESERVED);
+ return ulc;
+}
+
+struct gprs_rlcmac_pdch_ulc_node *gprs_rlcmac_pdch_ulc_get_node(struct
gprs_rlcmac_pdch_ulc *ulc, uint32_t fn)
+{
+ OSMO_ASSERT(ulc);
+ struct rb_node *node = ulc->tree_root.rb_node;
+ struct gprs_rlcmac_pdch_ulc_node *it;
+ int res;
+
+ while (node) {
+ it = rb_entry(node, struct gprs_rlcmac_pdch_ulc_node, node);
+ res = fn_cmp(it->fn, fn);
+ if (res > 0) /* it->fn AFTER fn */
+ node = node->rb_left;
+ else if (res < 0) /* it->fn BEFORE fn */
+ node = node->rb_right;
+ else /* it->fn == fn */
+ return it;
+ }
+ return NULL;
+}
+struct gprs_rlcmac_pdch_ulc_node *gprs_rlcmac_pdch_ulc_pop_node(struct
gprs_rlcmac_pdch_ulc *ulc, uint32_t fn)
+{
+ struct gprs_rlcmac_pdch_ulc_node *item = gprs_rlcmac_pdch_ulc_get_node(ulc, fn);
+ if (!item)
+ return NULL;
+ rb_erase(&item->node, &ulc->tree_root);
+ return item;
+}
+
+struct rrbp_opt {
+ uint8_t offset;
+ enum gprs_rlcmac_rrbp_field coding;
+};
+
+static struct gprs_rlcmac_pdch_ulc_node *_alloc_node(struct gprs_rlcmac_pdch_ulc *ulc,
uint32_t fn)
+{
+ struct gprs_rlcmac_pdch_ulc_node *node;
+ node = talloc_zero(ulc->pool_ctx, struct gprs_rlcmac_pdch_ulc_node);
+ node->fn = fn;
+ return node;
+}
+
+static int gprs_rlcmac_pdch_ulc_add_node(struct gprs_rlcmac_pdch_ulc *ulc, struct
gprs_rlcmac_pdch_ulc_node *item)
+{
+ struct rb_node **n = &(ulc->tree_root.rb_node);
+ struct rb_node *parent = NULL;
+
+ while (*n) {
+ struct gprs_rlcmac_pdch_ulc_node *it;
+ int res;
+
+ it = container_of(*n, struct gprs_rlcmac_pdch_ulc_node, node);
+
+ parent = *n;
+ res = fn_cmp(item->fn, it->fn);
+ if (res < 0) { /* item->fn "BEFORE" it->fn */
+ n = &((*n)->rb_left);
+ } else if (res > 0) { /* item->fn "AFTER" it->fn */
+ n = &((*n)->rb_right);
+ } else {
+ LOGRLCMAC(LOGL_ERROR, "TS=%" PRIu8 " Trying to reserve already reserved
FN %u\n",
+ ulc->ts_nr, item->fn);
+ return -EEXIST;
+ }
+ }
+
+ rb_link_node(&item->node, parent, n);
+ rb_insert_color(&item->node, &ulc->tree_root);
+ return 0;
+}
+
+int gprs_rlcmac_pdch_ulc_reserve(struct gprs_rlcmac_pdch_ulc *ulc, uint32_t fn,
+ enum gprs_rlcmac_pdch_ulc_poll_reason reason,
+ struct gprs_rlcmac_tbf *tbf)
+{
+ struct gprs_rlcmac_pdch_ulc_node *item = _alloc_node(ulc, fn);
+ item->reason = reason;
+ item->tbf = tbf;
+ LOGRLCMAC(LOGL_DEBUG, "Register POLL (TS=%u FN=%u, reason=%s)\n",
+ ulc->ts_nr, item->fn,
+ get_value_string(gprs_rlcmac_pdch_ulc_poll_reason_names, item->reason));
+ return gprs_rlcmac_pdch_ulc_add_node(ulc, item);
+}
+
+void gprs_rlcmac_pdch_ulc_release_node(struct gprs_rlcmac_pdch_ulc *ulc, struct
gprs_rlcmac_pdch_ulc_node *item)
+{
+ rb_erase(&item->node, &ulc->tree_root);
+ talloc_free(item);
+}
+
+int gprs_rlcmac_pdch_ulc_release_fn(struct gprs_rlcmac_pdch_ulc *ulc, uint32_t fn)
+{
+ struct gprs_rlcmac_pdch_ulc_node *item = gprs_rlcmac_pdch_ulc_get_node(ulc, fn);
+ if (!item)
+ return -ENOKEY;
+ gprs_rlcmac_pdch_ulc_release_node(ulc, item);
+ return 0;
+}
+
+void gprs_rlcmac_pdch_ulc_release_tbf(struct gprs_rlcmac_pdch_ulc *ulc, const struct
gprs_rlcmac_tbf *tbf)
+{
+ bool tree_modified;
+ do {
+ struct rb_node *node;
+ struct gprs_rlcmac_pdch_ulc_node *item;
+
+ tree_modified = false;
+ for (node = rb_first(&ulc->tree_root); node; node = rb_next(node)) {
+ item = container_of(node, struct gprs_rlcmac_pdch_ulc_node, node);
+ if (item->tbf != tbf)
+ continue;
+ /* One entry found, remove it from tree and restart
+ * search from start (to avoid traverse continue from
+ * no-more existent node */
+ tree_modified = true;
+ gprs_rlcmac_pdch_ulc_release_node(ulc, item);
+ break;
+ }
+ } while (tree_modified);
+}
+
+void gprs_rlcmac_pdch_ulc_expire_fn(struct gprs_rlcmac_pdch_ulc *ulc, uint32_t fn)
+{
+ struct gprs_rlcmac_pdch_ulc_node *item;
+ int res;
+
+ struct rb_node *first;
+ while ((first = rb_first(&ulc->tree_root))) {
+ item = container_of(first, struct gprs_rlcmac_pdch_ulc_node, node);
+ res = fn_cmp(item->fn, fn);
+ if (res > 0) /* item->fn AFTER fn */
+ break;
+ if (res < 0) { /* item->fn BEFORE fn */
+ /* Sanity check: */
+ LOGRLCMAC(LOGL_ERROR,
+ "TS=%" PRIu8 " Expiring FN=%" PRIu32 " but previous
FN=%" PRIu32 " is still reserved!\n",
+ ulc->ts_nr, fn, item->fn);
+ }
+ rb_erase(&item->node, &ulc->tree_root);
+
+ LOGRLCMAC(LOGL_NOTICE, "TS=%u Timeout for registered POLL (FN=%u,
reason=%s)\n",
+ ulc->ts_nr, item->fn, get_value_string(gprs_rlcmac_pdch_ulc_poll_reason_names,
item->reason));
+
+ talloc_free(item);
+ }
+}
diff --git a/src/rlcmac/rlcmac.c b/src/rlcmac/rlcmac.c
index 5b72690..1e28bac 100644
--- a/src/rlcmac/rlcmac.c
+++ b/src/rlcmac/rlcmac.c
@@ -27,6 +27,7 @@
#include <osmocom/gprs/rlcmac/rlcmac_prim.h>
#include <osmocom/gprs/rlcmac/rlcmac_private.h>
#include <osmocom/gprs/rlcmac/rlcmac_dec.h>
+#include <osmocom/gprs/rlcmac/pdch_ul_controller.h>
#include <osmocom/gprs/rlcmac/tbf_ul_fsm.h>
#include <osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h>
#include <osmocom/gprs/rlcmac/gre.h>
@@ -58,6 +59,7 @@
{
bool first_init = true;
int rc;
+ unsigned int i;
OSMO_ASSERT(location == OSMO_GPRS_RLCMAC_LOCATION_MS || location ==
OSMO_GPRS_RLCMAC_LOCATION_PCU)
if (g_ctx) {
@@ -94,6 +96,11 @@
}
}
+ for (i = 0; i < ARRAY_SIZE(g_ctx->sched.ulc); i++) {
+ g_ctx->sched.ulc[i] = gprs_rlcmac_pdch_ulc_alloc(g_ctx, i);
+ OSMO_ASSERT(g_ctx->sched.ulc[i]);
+ }
+
return 0;
}
@@ -324,7 +331,8 @@
return -ENOENT;
}
LOGPTBFDL(dl_tbf, LOGL_DEBUG, "Rx new DL data\n");
- rc = gprs_rlcmac_dl_tbf_rcv_data_block(dl_tbf, &rlc_dec,
rlcmac_prim->l1ctl.pdch_data_ind.data);
+ rc = gprs_rlcmac_dl_tbf_rcv_data_block(dl_tbf, &rlc_dec,
rlcmac_prim->l1ctl.pdch_data_ind.data,
+ rlcmac_prim->l1ctl.pdch_data_ind.fn,
rlcmac_prim->l1ctl.pdch_data_ind.ts_nr);
return rc;
}
diff --git a/src/rlcmac/sched.c b/src/rlcmac/sched.c
index ea133c5..f229b7a 100644
--- a/src/rlcmac/sched.c
+++ b/src/rlcmac/sched.c
@@ -25,19 +25,85 @@
#include <osmocom/gprs/rlcmac/rlcmac_private.h>
#include <osmocom/gprs/rlcmac/sched.h>
#include <osmocom/gprs/rlcmac/gre.h>
+#include <osmocom/gprs/rlcmac/tbf_dl.h>
#include <osmocom/gprs/rlcmac/tbf_ul.h>
#include <osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h>
+#include <osmocom/gprs/rlcmac/types_private.h>
+#include <osmocom/gprs/rlcmac/pdch_ul_controller.h>
struct tbf_sched_ctrl_candidates {
+ struct gprs_rlcmac_dl_tbf *poll_dl_ack_final_ack; /* 8.1.2.2 1) */
+ struct gprs_rlcmac_dl_tbf *poll_dl_ack; /* 8.1.2.2 7) */
struct gprs_rlcmac_ul_tbf *ul_ass;
};
+static inline uint32_t next_fn(uint32_t fn, uint32_t offset)
+{
+ return (fn + offset) % GSM_MAX_FN;
+}
+
+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;
+ static const uint8_t rrbp_list[] = {
+ 13, /* GPRS_RLCMAC_RRBP_N_plus_13 */
+ 17, /* GPRS_RLCMAC_RRBP_N_plus_17_18 */
+ 21, /* GPRS_RLCMAC_RRBP_N_plus_21_22 */
+ 26, /* GPRS_RLCMAC_RRBP_N_plus_26 */
+ };
+
+ OSMO_ASSERT(rrbp < ARRAY_SIZE(rrbp_list));
+
+ poll_fn = next_fn(cur_fn, rrbp_list[rrbp]);
+ if (!fn_valid(poll_fn)) {
+ /* 17 -> 18, 21 -> 22: */
+ poll_fn = next_fn(poll_fn, 1);
+ OSMO_ASSERT(fn_valid(poll_fn));
+ }
+ return poll_fn;
+}
+
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_dl_tbf *dl_tbf;
struct gprs_rlcmac_ul_tbf *ul_tbf;
+ struct gprs_rlcmac_pdch_ulc_node *node;
+
+ node = gprs_rlcmac_pdch_ulc_get_node(g_ctx->sched.ulc[bi->ts], bi->fn);
+ if (node) {
+ switch (node->reason) {
+ case GPRS_RLCMAC_PDCH_ULC_POLL_UL_ASS:
+ /* TODO */
+ break;
+ case GPRS_RLCMAC_PDCH_ULC_POLL_DL_ASS:
+ /* TODO */
+ break;
+ case GPRS_RLCMAC_PDCH_ULC_POLL_UL_ACK:
+ /* TODO */
+ break;
+ case GPRS_RLCMAC_PDCH_ULC_POLL_DL_ACK:
+ dl_tbf = tbf_as_dl_tbf(node->tbf);
+ /* 8.1.2.2 Polling for Packet Downlink Ack/Nack */
+ if (gprs_rlcmac_tbf_dl_state(dl_tbf) == GPRS_RLCMAC_TBF_DL_ST_FINISHED)
+ tbfs->poll_dl_ack_final_ack = dl_tbf;
+ else
+ tbfs->poll_dl_ack = dl_tbf;
+ break;
+ case GPRS_RLCMAC_PDCH_ULC_POLL_CELL_CHG_CONTINUE:
+ /* TODO */
+ break;
+ }
+ gprs_rlcmac_pdch_ulc_release_node(g_ctx->sched.ulc[bi->ts], node);
+ }
/* Iterate over UL TBFs: */
llist_for_each_entry(gre, &g_ctx->gre_list, entry) {
@@ -75,13 +141,38 @@
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)
+ /* 8.1.2.2 1) (EGPRS) PACKET DOWNLINK ACK/NACK w/ FinalAckInd=1 */
+ if (tbfs->poll_dl_ack_final_ack) {
+ LOGRLCMAC(LOGL_DEBUG, "(ts=%u,fn=%u,usf=%u) Tx DL ACK/NACK FinalAck=1\n",
+ bi->ts, bi->fn, bi->usf);
+ msg = NULL; /* TODO: generate DL ACK/NACK ctrl block */
+ if (msg)
+ return msg;
+ }
+
+ /* 8.1.2.2 5) Any other RLC/MAC control message, other than a (EGPRS) PACKET DOWNLINK
ACK/NACK */
+ if (tbfs->ul_ass) {
msg = gprs_rlcmac_tbf_ul_ass_create_rlcmac_msg(tbfs->ul_ass, bi);
- return msg;
+ if (msg)
+ return msg;
+ }
+
+ /* 8.1.2.2 7) A (EGPRS) PACKET DOWNLINK ACK/NACK message not containing a Final Ack
Indicator or a
+ * Channel Request Description IE */
+ if (tbfs->poll_dl_ack) {
+ LOGRLCMAC(LOGL_DEBUG, "(ts=%u,fn=%u,usf=%u) Tx DL ACK/NACK\n",
+ bi->ts, bi->fn, bi->usf);
+ msg = NULL; /* TODO: generate DL ACK/NACK ctrl block */
+ if (msg)
+ return msg;
+ }
+
+ return NULL;
}
static struct msgb *sched_select_ul_data_msg(const struct gprs_rlcmac_rts_block_ind *bi)
@@ -116,7 +207,7 @@
struct msgb *msg = NULL;
struct tbf_sched_ctrl_candidates tbf_cand = {0};
struct osmo_gprs_rlcmac_prim *rlcmac_prim_tx;
- int rc;
+ int rc = 0;
get_ctrl_msg_tbf_candidates(bi, &tbf_cand);
@@ -126,17 +217,20 @@
if ((msg = sched_select_ul_data_msg(bi)))
goto tx_msg;
- /* Prio 3: send dummy control message (or nothing depending on EXT_UTBF_NODATA) */
+ /* Lowest prio: 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;
+ goto ret_rc;
tx_msg:
rlcmac_prim_tx = gprs_rlcmac_prim_alloc_l1ctl_pdch_data_req(bi->ts, bi->fn,
msgb_data(msg), 0);
rlcmac_prim_tx->l1ctl.pdch_data_req.data_len = msgb_length(msg);
rc = gprs_rlcmac_prim_call_down_cb(rlcmac_prim_tx);
msgb_free(msg);
+
+ret_rc:
+ gprs_rlcmac_pdch_ulc_expire_fn(g_ctx->sched.ulc[bi->ts], bi->fn);
return rc;
}
diff --git a/src/rlcmac/tbf_dl.c b/src/rlcmac/tbf_dl.c
index a5b342a..da9b871 100644
--- a/src/rlcmac/tbf_dl.c
+++ b/src/rlcmac/tbf_dl.c
@@ -24,6 +24,7 @@
#include <osmocom/gprs/rlcmac/gre.h>
#include <osmocom/gprs/rlcmac/rlc_window_dl.h>
#include <osmocom/gprs/rlcmac/rlcmac_dec.h>
+#include <osmocom/gprs/rlcmac/pdch_ul_controller.h>
struct gprs_rlcmac_dl_tbf *gprs_rlcmac_dl_tbf_alloc(struct gprs_rlcmac_entity *gre)
{
@@ -167,7 +168,7 @@
int gprs_rlcmac_dl_tbf_rcv_data_block(struct gprs_rlcmac_dl_tbf *dl_tbf,
const struct gprs_rlcmac_rlc_data_info *rlc,
- uint8_t *data)
+ uint8_t *data, uint32_t fn, uint8_t ts_nr)
{
const struct gprs_rlcmac_rlc_block_info *rdbi;
struct gprs_rlcmac_rlc_block *block;
@@ -257,7 +258,13 @@
}
}
- /* TODO: if RRBP contains valid data, schedule a DL ACK/NACK. */
+ /* If RRBP contains valid data, schedule a DL ACK/NACK. */
+ if (rlc->es_p) {
+ uint32_t poll_fn = rrbp2fn(fn, rlc->rrbp);
+ gprs_rlcmac_pdch_ulc_reserve(g_ctx->sched.ulc[ts_nr], poll_fn,
+ GPRS_RLCMAC_PDCH_ULC_POLL_DL_ACK,
+ dl_tbf_as_tbf(dl_tbf));
+ }
return 0;
}
diff --git a/tests/rlcmac/rlcmac_prim_test.c b/tests/rlcmac/rlcmac_prim_test.c
index 283227b..c80ce60 100644
--- a/tests/rlcmac/rlcmac_prim_test.c
+++ b/tests/rlcmac/rlcmac_prim_test.c
@@ -25,6 +25,8 @@
#include <osmocom/gprs/rlcmac/rlcmac.h>
#include <osmocom/gprs/rlcmac/gre.h>
#include <osmocom/gprs/rlcmac/rlc.h>
+#include <osmocom/gprs/rlcmac/types_private.h>
+#include <osmocom/gprs/rlcmac/sched.h>
static void *tall_ctx = NULL;
@@ -241,7 +243,7 @@
0x43, 0xc0, 0x01, 0x2b, 0x2b, 0x2b
};
-static struct msgb *create_dl_data_block(uint8_t dl_tfi, uint8_t usf, enum
gprs_rlcmac_coding_scheme cs, uint8_t bsn, bool fbi)
+static struct msgb *create_dl_data_block(uint8_t dl_tfi, uint8_t usf, enum
gprs_rlcmac_coding_scheme cs, uint8_t bsn, bool fbi, bool s_p, uint8_t rrbp)
{
struct msgb *msg = msgb_alloc(128, __func__);
struct gprs_rlcmac_rlc_dl_data_header *hdr;
@@ -249,8 +251,8 @@
hdr = (struct gprs_rlcmac_rlc_dl_data_header *)msgb_put(msg,
gprs_rlcmac_mcs_size_dl(cs));
hdr->pt = 0; /* RLC/MAC block contains an RLC data block */
- hdr->rrbp = 0;
- hdr->s_p = 0;
+ hdr->rrbp = rrbp;
+ hdr->s_p = s_p ? 1 : 0;
hdr->usf = usf;
hdr->pr = 0;
hdr->tfi = dl_tfi;
@@ -330,6 +332,7 @@
uint8_t usf = 0;
uint32_t rts_fn = 4;
uint8_t dl_tfi = 0;
+ uint8_t rrbp = GPRS_RLCMAC_RRBP_N_plus_17_18;
/* Notify RLCMAC about our TLLI */
rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_gmmrr_assign_req(tlli);
@@ -341,7 +344,7 @@
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, 1);
+ 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));
@@ -349,6 +352,12 @@
OSMO_ASSERT(rc == 0);
msgb_free(dl_data_msg);
+ /* Trigger transmission of DL ACK/NACK */
+ 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);
+
printf("=== %s end ===\n", __func__);
cleanup_test();
}
diff --git a/tests/rlcmac/rlcmac_prim_test.err b/tests/rlcmac/rlcmac_prim_test.err
index 41f88a7..2d1b804 100644
--- a/tests/rlcmac/rlcmac_prim_test.err
+++ b/tests/rlcmac/rlcmac_prim_test.err
@@ -38,7 +38,7 @@
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=0 RRBP=0, E=0, bitoffs=24
+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
@@ -51,3 +51,8 @@
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 lower layers: L1CTL-PDCH_RTS.indication
+DLGLOBAL DEBUG (ts=7,fn=21,usf=0) Tx DL ACK/NACK FinalAck=1
+DLGLOBAL DEBUG (ts=7,fn=21,usf=0) No Uplink TBF available to transmit RLC/MAC Ul Data
Block
+DLGLOBAL DEBUG (ts=7,fn=21,usf=0) No Uplink TBF available to transmit RLC/MAC Ul Dummy
Ctrl Block
--
To view, visit
https://gerrit.osmocom.org/c/libosmo-gprs/+/31325
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: libosmo-gprs
Gerrit-Branch: master
Gerrit-Change-Id: I9d38a8de4240e65585cc8bbe3c044473af5a83e5
Gerrit-Change-Number: 31325
Gerrit-PatchSet: 4
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged