aboutsummaryrefslogtreecommitdiffstats
path: root/src/tbf_dl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tbf_dl.cpp')
-rw-r--r--src/tbf_dl.cpp133
1 files changed, 68 insertions, 65 deletions
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index c1148693..68e6fab7 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -99,36 +99,29 @@ int gprs_rlcmac_dl_tbf::append_data(const uint8_t ms_class,
const uint8_t *data, const uint16_t len)
{
LOGP(DRLCMAC, LOGL_INFO, "%s append\n", tbf_name(this));
+ /* TODO: put this path into an llc_enqueue method */
+ /* the TBF exists, so we must write it in the queue
+ * we prepend lifetime in front of PDU */
+ struct timeval *tv;
+ struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv) * 2,
+ "llc_pdu_queue");
+ if (!llc_msg)
+ return -ENOMEM;
+ tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
+ gprs_llc_queue::calc_pdu_lifetime(bts, pdu_delay_csec, tv);
+ tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
+ gettimeofday(tv, NULL);
+ memcpy(msgb_put(llc_msg, len), data, len);
+ llc_queue()->enqueue(llc_msg);
+ tbf_update_ms_class(this, ms_class);
+ start_llc_timer();
+
if (state_is(GPRS_RLCMAC_WAIT_RELEASE)) {
LOGP(DRLCMAC, LOGL_DEBUG,
"%s in WAIT RELEASE state "
"(T3193), so reuse TBF\n", tbf_name(this));
tbf_update_ms_class(this, ms_class);
- reuse_tbf(data, len);
- } else if (!have_data()) {
- m_llc.put_frame(data, len);
- bts->llc_frame_sched();
- /* it is no longer drained */
- m_last_dl_drained_fn = -1;
- tbf_update_ms_class(this, ms_class);
- start_llc_timer();
- } else {
- /* TODO: put this path into an llc_enqueue method */
- /* the TBF exists, so we must write it in the queue
- * we prepend lifetime in front of PDU */
- struct timeval *tv;
- struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv) * 2,
- "llc_pdu_queue");
- if (!llc_msg)
- return -ENOMEM;
- tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
- gprs_llc_queue::calc_pdu_lifetime(bts, pdu_delay_csec, tv);
- tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
- gettimeofday(tv, NULL);
- memcpy(msgb_put(llc_msg, len), data, len);
- llc_queue()->enqueue(llc_msg);
- tbf_update_ms_class(this, ms_class);
- start_llc_timer();
+ reuse_tbf();
}
return 0;
@@ -149,7 +142,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
const char *imsi,
const uint32_t tlli, const uint32_t tlli_old,
const uint8_t ms_class,
- const uint8_t *data, const uint16_t len)
+ struct gprs_rlcmac_dl_tbf **tbf)
{
uint8_t trx, ss;
int8_t use_trx;
@@ -188,9 +181,6 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
if (!dl_tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
- bssgp_tx_llc_discarded(gprs_bssgp_pcu_current_bctx(), tlli,
- 1, len);
- bts->bts->llc_dropped_frame();
return -EBUSY;
}
dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
@@ -198,10 +188,6 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
LOGP(DRLCMAC, LOGL_DEBUG, "%s [DOWNLINK] START\n", tbf_name(dl_tbf));
- /* new TBF, so put first frame */
- dl_tbf->m_llc.put_frame(data, len);
- dl_tbf->bts->llc_frame_sched();
-
/* Store IMSI for later look-up and PCH retransmission */
dl_tbf->assign_imsi(imsi);
@@ -210,6 +196,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
* to trigger downlink assignment. if there is no uplink,
* AGCH is used. */
dl_tbf->bts->trigger_dl_ass(dl_tbf, old_ul_tbf);
+ *tbf = dl_tbf;
return 0;
}
@@ -222,20 +209,30 @@ int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
const uint8_t *data, const uint16_t len)
{
struct gprs_rlcmac_dl_tbf *dl_tbf;
+ int rc;
+ GprsMs *ms;
/* check for existing TBF */
dl_tbf = tbf_lookup_dl(bts->bts, tlli, tlli_old, imsi);
- if (dl_tbf) {
- int rc = dl_tbf->append_data(ms_class, delay_csec, data, len);
- if (rc >= 0)
- dl_tbf->assign_imsi(imsi);
+ if (!dl_tbf) {
+ rc = tbf_new_dl_assignment(bts, imsi, tlli, tlli_old, ms_class,
+ &dl_tbf);
+ if (rc < 0)
+ return rc;
+ }
- if (dl_tbf->ms())
- dl_tbf->ms()->confirm_tlli(tlli);
- return rc;
- }
+ OSMO_ASSERT(dl_tbf->ms() != NULL);
+ ms = dl_tbf->ms();
+ GprsMs::Guard guard(ms);
- return tbf_new_dl_assignment(bts, imsi, tlli, tlli_old, ms_class, data, len);
+ rc = dl_tbf->append_data(ms_class, delay_csec, data, len);
+
+ dl_tbf = ms->dl_tbf();
+
+ dl_tbf->assign_imsi(imsi);
+ ms->confirm_tlli(tlli);
+
+ return rc;
}
struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
@@ -385,17 +382,41 @@ do_resend:
goto do_resend;
}
+void gprs_rlcmac_dl_tbf::schedule_next_frame()
+{
+ struct msgb *msg;
+
+ if (m_llc.frame_length() != 0)
+ return;
+
+ /* dequeue next LLC frame, if any */
+ msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
+ if (!msg)
+ return;
+
+ LOGP(DRLCMACDL, LOGL_INFO,
+ "- Dequeue next LLC for %s (len=%d)\n",
+ tbf_name(this), msg->len);
+
+ m_llc.put_frame(msg->data, msg->len);
+ bts->llc_frame_sched();
+ msgb_free(msg);
+ m_last_dl_drained_fn = -1;
+}
+
struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t ts)
{
struct rlc_dl_header *rh;
struct rlc_li_field *li;
- struct msgb *msg;
uint8_t *delimiter, *data, *e_pointer;
uint16_t space, chunk;
gprs_rlc_data *rlc_data;
const uint16_t bsn = m_window.v_s();
uint8_t cs = 1;
+ if (m_llc.frame_length() == 0)
+ schedule_next_frame();
+
cs = current_cs();
LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d, CS=%d\n",
@@ -535,15 +556,7 @@ struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t
gprs_rlcmac_dl_bw(this, m_llc.frame_length());
m_llc.reset();
/* dequeue next LLC frame, if any */
- msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
- if (msg) {
- LOGP(DRLCMACDL, LOGL_INFO, "- Dequeue next LLC for "
- "%s (len=%d)\n", tbf_name(this), msg->len);
- m_llc.put_frame(msg->data, msg->len);
- bts->llc_frame_sched();
- msgb_free(msg);
- m_last_dl_drained_fn = -1;
- }
+ schedule_next_frame();
/* if we have more data and we have space left */
if (space > 0 && (m_llc.frame_length() || keep_open(fn))) {
li->m = 1; /* we indicate more frames to follow */
@@ -796,7 +809,6 @@ int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
int gprs_rlcmac_dl_tbf::maybe_start_new_window()
{
- struct msgb *msg;
uint16_t received;
LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
@@ -809,8 +821,7 @@ int gprs_rlcmac_dl_tbf::maybe_start_new_window()
set_state(GPRS_RLCMAC_WAIT_RELEASE);
/* check for LLC PDU in the LLC Queue */
- msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
- if (!msg) {
+ if (!have_data()) {
/* no message, start T3193, change state to RELEASE */
LOGP(DRLCMACDL, LOGL_DEBUG, "- No new message, so we release.\n");
/* start T3193 */
@@ -822,8 +833,7 @@ int gprs_rlcmac_dl_tbf::maybe_start_new_window()
}
/* we have more data so we will re-use this tbf */
- reuse_tbf(msg->data, msg->len);
- msgb_free(msg);
+ reuse_tbf();
return 0;
}
@@ -836,7 +846,7 @@ int gprs_rlcmac_dl_tbf::rcvd_dl_ack(uint8_t final_ack, uint8_t ssn, uint8_t *rbb
return maybe_start_new_window();
}
-void gprs_rlcmac_dl_tbf::reuse_tbf(const uint8_t *data, const uint16_t len)
+void gprs_rlcmac_dl_tbf::reuse_tbf()
{
uint8_t trx;
struct gprs_rlcmac_dl_tbf *new_tbf = NULL;
@@ -851,18 +861,11 @@ void gprs_rlcmac_dl_tbf::reuse_tbf(const uint8_t *data, const uint16_t len)
if (!new_tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
- bssgp_tx_llc_discarded(gprs_bssgp_pcu_current_bctx(), tlli(),
- 1, len);
- bts->llc_dropped_frame();
return;
}
new_tbf->set_ms(ms());
- /* Start with the passed frame */
- new_tbf->m_llc.put_frame(data, len);
- bts->llc_frame_sched();
-
/* reset rlc states */
m_tx_counter = 0;
m_wait_confirm = 0;