aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gprs_bssgp_pcu.cpp15
-rw-r--r--src/gprs_rlcmac.cpp104
-rw-r--r--src/gprs_rlcmac.h8
-rw-r--r--src/gprs_rlcmac_data.cpp44
-rw-r--r--src/gprs_rlcmac_sched.cpp5
-rw-r--r--src/pcu_l1_if.cpp18
-rw-r--r--src/pcu_main.cpp2
7 files changed, 185 insertions, 11 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index 5dbfb2c1..54753b85 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -196,6 +196,7 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
uint8_t trx, ta, ss;
int8_t use_trx;
struct gprs_rlcmac_tbf *old_tbf;
+ int rc;
/* check for uplink data, so we copy our informations */
tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF);
@@ -207,7 +208,19 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
old_tbf = tbf;
} else {
use_trx = -1;
- ta = 0; /* FIXME: initial TA */
+ /* we already have an uplink TBF, so we use that TA */
+ if (tbf)
+ ta = tbf->ta;
+ else {
+ /* recall TA */
+ rc = recall_timing_advance(tlli);
+ if (rc < 0) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "TA unknown"
+ ", assuming 0\n");
+ ta = 0;
+ } else
+ ta = rc;
+ }
ss = 1; /* PCH assignment only allows one timeslot */
old_tbf = NULL;
}
diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp
index 2c873172..2ea0a614 100644
--- a/src/gprs_rlcmac.cpp
+++ b/src/gprs_rlcmac.cpp
@@ -1819,3 +1819,107 @@ int gprs_rlcmac_paging_request(uint8_t *ptmsi, uint16_t ptmsi_len,
return 0;
}
+
+
+/*
+ * timing advance memory
+ */
+
+/* enable to debug timing advance memory */
+//#define DEBUG_TA
+
+static LLIST_HEAD(gprs_rlcmac_ta_list);
+static int gprs_rlcmac_ta_num = 0;
+
+struct gprs_rlcmac_ta {
+ struct llist_head list;
+ uint32_t tlli;
+ uint8_t ta;
+};
+
+/* remember timing advance of a given TLLI */
+int remember_timing_advance(uint32_t tlli, uint8_t ta)
+{
+ struct gprs_rlcmac_ta *ta_entry;
+
+ /* check for existing entry */
+ llist_for_each_entry(ta_entry, &gprs_rlcmac_ta_list, list) {
+ if (ta_entry->tlli == tlli) {
+#ifdef DEBUG_TA
+ fprintf(stderr, "update %08x %d\n", tlli, ta);
+#endif
+ ta_entry->ta = ta;
+ /* relink to end of list */
+ llist_del(&ta_entry->list);
+ llist_add_tail(&ta_entry->list, &gprs_rlcmac_ta_list);
+ return 0;
+ }
+ }
+
+#ifdef DEBUG_TA
+ fprintf(stderr, "remember %08x %d\n", tlli, ta);
+#endif
+ /* if list is full, remove oldest entry */
+ if (gprs_rlcmac_ta_num == 30) {
+ ta_entry = llist_entry(gprs_rlcmac_ta_list.next,
+ struct gprs_rlcmac_ta, list);
+ llist_del(&ta_entry->list);
+ talloc_free(ta_entry);
+ gprs_rlcmac_ta_num--;
+ }
+
+ /* create new TA entry */
+ ta_entry = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ta);
+ if (!ta_entry)
+ return -ENOMEM;
+
+ ta_entry->tlli = tlli;
+ ta_entry->ta = ta;
+ llist_add_tail(&ta_entry->list, &gprs_rlcmac_ta_list);
+ gprs_rlcmac_ta_num++;
+
+ return 0;
+}
+
+int recall_timing_advance(uint32_t tlli)
+{
+ struct gprs_rlcmac_ta *ta_entry;
+ uint8_t ta;
+
+ llist_for_each_entry(ta_entry, &gprs_rlcmac_ta_list, list) {
+ if (ta_entry->tlli == tlli) {
+ ta = ta_entry->ta;
+#ifdef DEBUG_TA
+ fprintf(stderr, "recall %08x %d\n", tlli, ta);
+#endif
+ return ta;
+ }
+ }
+#ifdef DEBUG_TA
+ fprintf(stderr, "no entry for %08x\n", tlli);
+#endif
+
+ return -EINVAL;
+}
+
+int flush_timing_advance(void)
+{
+ struct gprs_rlcmac_ta *ta_entry;
+ int count = 0;
+
+ while (!llist_empty(&gprs_rlcmac_ta_list)) {
+ ta_entry = llist_entry(gprs_rlcmac_ta_list.next,
+ struct gprs_rlcmac_ta, list);
+#ifdef DEBUG_TA
+ fprintf(stderr, "flush entry %08x %d\n", ta_entry->tlli,
+ ta_entry->ta);
+#endif
+ llist_del(&ta_entry->list);
+ talloc_free(ta_entry);
+ count++;
+ }
+ gprs_rlcmac_ta_num = 0;
+
+ return count;
+}
+
diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h
index 5badb120..c5af6029 100644
--- a/src/gprs_rlcmac.h
+++ b/src/gprs_rlcmac.h
@@ -374,6 +374,8 @@ void tbf_timer_cb(void *_tbf);
int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf);
+int gprs_rlcmac_sba_timeout(struct gprs_rlcmac_sba *sba);
+
int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta);
int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
@@ -421,6 +423,12 @@ struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging(
struct msgb *gprs_rlcmac_send_packet_paging_request(
struct gprs_rlcmac_pdch *pdch);
+int remember_timing_advance(uint32_t tlli, uint8_t ta);
+
+int recall_timing_advance(uint32_t tlli);
+
+int flush_timing_advance(void);
+
extern "C" {
#endif
int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf,
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp
index 1109451e..4f2b649a 100644
--- a/src/gprs_rlcmac_data.cpp
+++ b/src/gprs_rlcmac_data.cpp
@@ -206,6 +206,15 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf)
return 0;
}
+int gprs_rlcmac_sba_timeout(struct gprs_rlcmac_sba *sba)
+{
+ LOGP(DRLCMAC, LOGL_NOTICE, "Poll timeout for SBA\n");
+ llist_del(&sba->list);
+ talloc_free(sba);
+
+ return 0;
+}
+
static uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
{
int i;
@@ -263,6 +272,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
int8_t tfi = 0; /* must be signed */
uint32_t tlli = 0;
struct gprs_rlcmac_tbf *tbf;
+ struct gprs_rlcmac_sba *sba;
int rc;
RlcMacUplink_t * ul_control_block = (RlcMacUplink_t *)talloc_zero(tall_pcu_ctx, RlcMacUplink_t);
@@ -420,6 +430,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
if (!tbf) {
uint8_t ms_class = 0;
struct gprs_rlcmac_tbf *dl_tbf;
+ uint8_t ta;
if ((dl_tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF))) {
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
@@ -431,12 +442,28 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF "
"in packet ressource request of single "
"block, so we provide one:\n");
+ sba = sba_find(trx, ts, fn);
+ if (!sba) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "MS requests UL TBF "
+ "in packet ressource request of single "
+ "block, but there is no resource request "
+ "scheduled!\n");
+ rc = recall_timing_advance(tlli);
+ if (rc >= 0)
+ ta = rc;
+ else
+ ta = 0;
+ } else {
+ ta = sba->ta;
+ remember_timing_advance(tlli, ta);
+ llist_del(&sba->list);
+ talloc_free(sba);
+ }
if (ul_control_block->u.Packet_Resource_Request.Exist_MS_Radio_Access_capability)
ms_class = get_ms_class_by_capability(&ul_control_block->u.Packet_Resource_Request.MS_Radio_Access_capability);
if (!ms_class)
LOGP(DRLCMAC, LOGL_NOTICE, "MS does not give us a class.\n");
- tbf = alloc_ul_tbf(trx, ms_class, tlli, 0, NULL);
-#warning FIXME TA!!!
+ tbf = alloc_ul_tbf(trx, ms_class, tlli, ta, NULL);
if (!tbf)
break;
/* set control ts to current MS's TS, until assignment complete */
@@ -469,6 +496,17 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
LOGP(DRLCMAC, LOGL_ERROR, "RX: [PCU <- BTS] %s TFI: %u TLLI: 0x%08x FIXME: Packet ressource request\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->tlli);
break;
case MT_PACKET_MEASUREMENT_REPORT:
+ sba = sba_find(trx, ts, fn);
+ if (!sba) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "MS send measurement "
+ "in packet ressource request of single "
+ "block, but there is no resource request "
+ "scheduled!\n");
+ } else {
+ remember_timing_advance(ul_control_block->u.Packet_Measurement_Report.TLLI, sba->ta);
+ llist_del(&sba->list);
+ talloc_free(sba);
+ }
gprs_rlcmac_meas_rep(&ul_control_block->u.Packet_Measurement_Report);
break;
default:
@@ -888,6 +926,8 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts,
}
/* mark TLLI valid now */
tbf->tlli_valid = 1;
+ /* store current timing advance */
+ remember_timing_advance(tbf->tlli, tbf->ta);
/* already have TLLI, but we stille get another one */
} else if (rh->ti) {
uint32_t tlli;
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index f588c47d..9b31fbc3 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -78,11 +78,8 @@ uint32_t sched_sba(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr)
sba_fn ++;
sba_fn = sba_fn % 2715648;
sba = sba_find(trx, ts, sba_fn);
- if (sba) {
- llist_del(&sba->list);
- talloc_free(sba);
+ if (sba)
return sba_fn;
- }
return 0xffffffff;
}
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index d7f5ec44..923070f1 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -516,6 +516,7 @@ bssgp_failed:
static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind)
{
struct gprs_rlcmac_tbf *tbf;
+ struct gprs_rlcmac_sba *sba, *sba2;
uint32_t elapsed;
uint8_t fn13 = time_ind->fn % 13;
@@ -531,18 +532,27 @@ static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind)
/* check for poll timeout */
llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) {
if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) {
- elapsed = (frame_number - tbf->poll_fn) % 2715648;
- if (elapsed >= 20 && elapsed < 200)
+ elapsed = (frame_number + 2715648 - tbf->poll_fn)
+ % 2715648;
+ if (elapsed >= 20 && elapsed < 2715400)
gprs_rlcmac_poll_timeout(tbf);
}
}
llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) {
if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) {
- elapsed = (frame_number - tbf->poll_fn) % 2715648;
- if (elapsed >= 20 && elapsed < 200)
+ elapsed = (frame_number + 2715648 - tbf->poll_fn)
+ % 2715648;
+ if (elapsed >= 20 && elapsed < 2715400)
gprs_rlcmac_poll_timeout(tbf);
}
}
+ llist_for_each_entry_safe(sba, sba2, &gprs_rlcmac_sbas, list) {
+ elapsed = (frame_number + 2715648 - sba->fn) % 2715648;
+ if (elapsed >= 20 && elapsed < 2715400) {
+ /* sba will be freed here */
+ gprs_rlcmac_sba_timeout(sba);
+ }
+ }
return 0;
}
diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp
index 4f23dd76..041831f6 100644
--- a/src/pcu_main.cpp
+++ b/src/pcu_main.cpp
@@ -248,6 +248,8 @@ int main(int argc, char *argv[])
pcu_l1if_close();
+ flush_timing_advance();
+
talloc_free(gprs_rlcmac_bts);
talloc_report_full(tall_pcu_ctx, stderr);