blob: 442aa36978ead32dc40380e64063e01377288e41 [file] [log] [blame]
Daniel Willmannca102af2014-08-08 12:14:12 +02001/* Copied from tbf.cpp
2 *
3 * Copyright (C) 2012 Ivan Klyuchnikov
4 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
5 * Copyright (C) 2013 by Holger Hans Peter Freyther
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22#include <bts.h>
23#include <tbf.h>
24#include <rlc.h>
25#include <gprs_rlcmac.h>
26#include <gprs_debug.h>
27#include <gprs_bssgp_pcu.h>
28#include <decoding.h>
29
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +010030#include "pcu_utils.h"
31
Daniel Willmannca102af2014-08-08 12:14:12 +020032extern "C" {
33#include <osmocom/core/msgb.h>
34#include <osmocom/core/talloc.h>
35}
36
37#include <errno.h>
38#include <string.h>
39
40/* After sending these frames, we poll for ack/nack. */
41#define POLL_ACK_AFTER_FRAMES 20
42
43
44static const struct gprs_rlcmac_cs gprs_rlcmac_cs[] = {
45/* frame length data block max payload */
46 { 0, 0, 0 },
47 { 23, 23, 20 }, /* CS-1 */
48 { 34, 33, 30 }, /* CS-2 */
49 { 40, 39, 36 }, /* CS-3 */
50 { 54, 53, 50 }, /* CS-4 */
51};
52
53extern "C" {
54int bssgp_tx_llc_discarded(struct bssgp_bvc_ctx *bctx, uint32_t tlli,
55 uint8_t num_frames, uint32_t num_octets);
56}
57
58static inline void tbf_update_ms_class(struct gprs_rlcmac_tbf *tbf,
59 const uint8_t ms_class)
60{
61 if (!tbf->ms_class && ms_class)
62 tbf->ms_class = ms_class;
63}
64
Jacob Erlbeckd0261b72015-04-02 13:58:09 +020065static void llc_timer_cb(void *_tbf)
66{
67 struct gprs_rlcmac_dl_tbf *tbf = (struct gprs_rlcmac_dl_tbf *)_tbf;
68
69 if (tbf->state_is_not(GPRS_RLCMAC_FLOW))
70 return;
71
72 LOGP(DRLCMAC, LOGL_DEBUG,
73 "%s LLC receive timeout, requesting DL ACK\n", tbf_name(tbf));
74
75 tbf->request_dl_ack();
76}
77
78void gprs_rlcmac_dl_tbf::cleanup()
79{
80 osmo_timer_del(&m_llc_timer);
81}
82
83void gprs_rlcmac_dl_tbf::start_llc_timer()
84{
85 if (bts_data()->llc_idle_ack_csec > 0) {
86 struct timeval tv;
87
88 /* TODO: this ought to be within a constructor */
89 m_llc_timer.data = this;
90 m_llc_timer.cb = &llc_timer_cb;
91
92 csecs_to_timeval(bts_data()->llc_idle_ack_csec, &tv);
93 osmo_timer_schedule(&m_llc_timer, tv.tv_sec, tv.tv_usec);
94 }
95}
96
Daniel Willmannca102af2014-08-08 12:14:12 +020097int gprs_rlcmac_dl_tbf::append_data(const uint8_t ms_class,
98 const uint16_t pdu_delay_csec,
99 const uint8_t *data, const uint16_t len)
100{
101 LOGP(DRLCMAC, LOGL_INFO, "%s append\n", tbf_name(this));
102 if (state_is(GPRS_RLCMAC_WAIT_RELEASE)) {
103 LOGP(DRLCMAC, LOGL_DEBUG,
104 "%s in WAIT RELEASE state "
105 "(T3193), so reuse TBF\n", tbf_name(this));
106 tbf_update_ms_class(this, ms_class);
107 reuse_tbf(data, len);
Jacob Erlbeckc4952092015-03-24 11:04:19 +0100108 } else if (!have_data()) {
109 m_llc.put_frame(data, len);
Jacob Erlbeck502bd1f2015-03-20 14:26:05 +0100110 m_last_dl_drained_fn = -1;
Jacob Erlbeckc4952092015-03-24 11:04:19 +0100111 bts->llc_frame_sched();
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +0100112 /* it is no longer drained */
113 m_last_dl_drained_fn = -1;
Jacob Erlbeckc4952092015-03-24 11:04:19 +0100114 tbf_update_ms_class(this, ms_class);
Jacob Erlbeckd0261b72015-04-02 13:58:09 +0200115 start_llc_timer();
Daniel Willmannca102af2014-08-08 12:14:12 +0200116 } else {
Jacob Erlbeckd0261b72015-04-02 13:58:09 +0200117 /* TODO: put this path into an llc_enqueue method */
Daniel Willmannca102af2014-08-08 12:14:12 +0200118 /* the TBF exists, so we must write it in the queue
119 * we prepend lifetime in front of PDU */
120 struct timeval *tv;
121 struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv) * 2,
122 "llc_pdu_queue");
123 if (!llc_msg)
124 return -ENOMEM;
125 tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
126 gprs_llc::calc_pdu_lifetime(bts, pdu_delay_csec, tv);
127 tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
128 gettimeofday(tv, NULL);
129 memcpy(msgb_put(llc_msg, len), data, len);
130 m_llc.enqueue(llc_msg);
131 tbf_update_ms_class(this, ms_class);
Jacob Erlbeckd0261b72015-04-02 13:58:09 +0200132 start_llc_timer();
Daniel Willmannca102af2014-08-08 12:14:12 +0200133 }
134
135 return 0;
136}
137
138static struct gprs_rlcmac_dl_tbf *tbf_lookup_dl(BTS *bts,
139 const uint32_t tlli, const char *imsi)
140{
141 /* TODO: look up by IMSI first, then tlli, then old_tlli */
142 return bts->dl_tbf_by_tlli(tlli);
143}
144
145static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
146 const char *imsi,
147 const uint32_t tlli, const uint8_t ms_class,
148 const uint8_t *data, const uint16_t len)
149{
150 uint8_t trx, ta, ss;
151 int8_t use_trx;
152 struct gprs_rlcmac_ul_tbf *ul_tbf, *old_ul_tbf;
Jacob Erlbeck90de3a72015-04-09 19:18:59 +0200153 struct gprs_rlcmac_dl_tbf *dl_tbf = NULL;
Daniel Willmannca102af2014-08-08 12:14:12 +0200154 int8_t tfi; /* must be signed */
155 int rc;
156
157 /* check for uplink data, so we copy our informations */
158#warning "Do the same look up for IMSI, TLLI and OLD_TLLI"
159#warning "Refactor the below lines... into a new method"
160 ul_tbf = bts->bts->ul_tbf_by_tlli(tlli);
161 if (ul_tbf && ul_tbf->m_contention_resolution_done
162 && !ul_tbf->m_final_ack_sent) {
163 use_trx = ul_tbf->trx->trx_no;
164 ta = ul_tbf->ta;
165 ss = 0;
166 old_ul_tbf = ul_tbf;
167 } else {
168 use_trx = -1;
169 /* we already have an uplink TBF, so we use that TA */
170 if (ul_tbf)
171 ta = ul_tbf->ta;
172 else {
173 /* recall TA */
174 rc = bts->bts->timing_advance()->recall(tlli);
175 if (rc < 0) {
176 LOGP(DRLCMAC, LOGL_NOTICE, "TA unknown"
177 ", assuming 0\n");
178 ta = 0;
179 } else
180 ta = rc;
181 }
182 ss = 1; /* PCH assignment only allows one timeslot */
183 old_ul_tbf = NULL;
184 }
185
186 // Create new TBF (any TRX)
187#warning "Copy and paste with alloc_ul_tbf"
188 tfi = bts->bts->tfi_find_free(GPRS_RLCMAC_DL_TBF, &trx, use_trx);
Jacob Erlbeck90de3a72015-04-09 19:18:59 +0200189 if (tfi >= 0)
190 /* set number of downlink slots according to multislot class */
191 dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf, tfi, trx, ms_class, ss);
192
Daniel Willmannca102af2014-08-08 12:14:12 +0200193 if (!dl_tbf) {
194 LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
Jacob Erlbeck90de3a72015-04-09 19:18:59 +0200195 bssgp_tx_llc_discarded(gprs_bssgp_pcu_current_bctx(), tlli,
196 1, len);
Daniel Willmannca102af2014-08-08 12:14:12 +0200197 return -EBUSY;
198 }
199 dl_tbf->m_tlli = tlli;
200 dl_tbf->m_tlli_valid = 1;
201 dl_tbf->ta = ta;
202
203 LOGP(DRLCMAC, LOGL_DEBUG, "%s [DOWNLINK] START\n", tbf_name(dl_tbf));
204
205 /* new TBF, so put first frame */
206 dl_tbf->m_llc.put_frame(data, len);
207 dl_tbf->bts->llc_frame_sched();
208
209 /* Store IMSI for later look-up and PCH retransmission */
210 dl_tbf->assign_imsi(imsi);
211
212 /* trigger downlink assignment and set state to ASSIGN.
213 * we don't use old_downlink, so the possible uplink is used
214 * to trigger downlink assignment. if there is no uplink,
215 * AGCH is used. */
216 dl_tbf->bts->trigger_dl_ass(dl_tbf, old_ul_tbf, imsi);
217 return 0;
218}
219
220/**
221 * TODO: split into unit test-able parts...
222 */
223int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
224 const uint32_t tlli, const char *imsi,
225 const uint8_t ms_class, const uint16_t delay_csec,
226 const uint8_t *data, const uint16_t len)
227{
228 struct gprs_rlcmac_dl_tbf *dl_tbf;
229
230 /* check for existing TBF */
231 dl_tbf = tbf_lookup_dl(bts->bts, tlli, imsi);
232 if (dl_tbf) {
233 int rc = dl_tbf->append_data(ms_class, delay_csec, data, len);
234 if (rc >= 0)
235 dl_tbf->assign_imsi(imsi);
236 return rc;
237 }
238
239 return tbf_new_dl_assignment(bts, imsi, tlli, ms_class, data, len);
240}
241
242struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
243{
244 struct msgb *msg;
Jacob Erlbeck0c1c8772015-03-20 12:02:42 +0100245 struct timeval *tv, tv_now, tv_now2;
Daniel Willmannca102af2014-08-08 12:14:12 +0200246 uint32_t octets = 0, frames = 0;
Jacob Erlbeck0c1c8772015-03-20 12:02:42 +0100247 struct timeval hyst_delta = {0, 0};
248 const unsigned keep_small_thresh = 60;
249
250 if (bts_data()->llc_discard_csec)
251 csecs_to_timeval(bts_data()->llc_discard_csec, &hyst_delta);
Daniel Willmannca102af2014-08-08 12:14:12 +0200252
253 gettimeofday(&tv_now, NULL);
Jacob Erlbeck0c1c8772015-03-20 12:02:42 +0100254 timeradd(&tv_now, &hyst_delta, &tv_now2);
Daniel Willmannca102af2014-08-08 12:14:12 +0200255
256 while ((msg = m_llc.dequeue())) {
257 tv = (struct timeval *)msg->data;
258 msgb_pull(msg, sizeof(*tv));
259 msgb_pull(msg, sizeof(*tv));
260
Jacob Erlbeck0c1c8772015-03-20 12:02:42 +0100261 /* Is the age below the low water mark? */
262 if (!gprs_llc::is_frame_expired(&tv_now2, tv))
263 break;
264
265 /* Is the age below the high water mark */
266 if (!gprs_llc::is_frame_expired(&tv_now, tv)) {
267 /* Has the previous message not been dropped? */
268 if (frames == 0)
269 break;
270
271 /* Hysteresis mode, try to discard LLC messages until
272 * the low water mark has been reached */
273
274 /* Check whether to abort the hysteresis mode */
275
276 /* Is the frame small, perhaps only a TCP ACK? */
277 if (msg->len <= keep_small_thresh)
278 break;
279
280 /* Is it a GMM message? */
281 if (!gprs_llc::is_user_data_frame(msg->data, msg->len))
282 break;
Daniel Willmannca102af2014-08-08 12:14:12 +0200283 }
Jacob Erlbeck0c1c8772015-03-20 12:02:42 +0100284
285 bts->llc_timedout_frame();
286 frames++;
287 octets += msg->len;
288 msgb_free(msg);
289 continue;
Daniel Willmannca102af2014-08-08 12:14:12 +0200290 }
291
292 if (frames) {
Jacob Erlbeck0c1c8772015-03-20 12:02:42 +0100293 LOGP(DRLCMACDL, LOGL_NOTICE, "%s Discarding LLC PDU "
294 "because lifetime limit reached, "
295 "count=%u new_queue_size=%zu\n",
296 tbf_name(this), frames, m_llc.m_queue_size);
Daniel Willmannca102af2014-08-08 12:14:12 +0200297 if (frames > 0xff)
298 frames = 0xff;
299 if (octets > 0xffffff)
300 octets = 0xffffff;
301 bssgp_tx_llc_discarded(bctx, m_tlli, frames, octets);
302 }
303
304 return msg;
305}
306
307/*
308 * Create DL data block
309 * The messages are fragmented and forwarded as data blocks.
310 */
311struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(uint32_t fn, uint8_t ts)
312{
313 LOGP(DRLCMACDL, LOGL_DEBUG, "%s downlink (V(A)==%d .. "
314 "V(S)==%d)\n", tbf_name(this),
315 m_window.v_a(), m_window.v_s());
316
317do_resend:
318 /* check if there is a block with negative acknowledgement */
319 int resend_bsn = m_window.resend_needed();
320 if (resend_bsn >= 0) {
321 LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d\n", resend_bsn);
322 /* re-send block with negative aknowlegement */
323 m_window.m_v_b.mark_unacked(resend_bsn);
324 bts->rlc_resent();
Jacob Erlbeck7c444152015-03-12 12:08:54 +0100325 return create_dl_acked_block(fn, ts, resend_bsn);
Daniel Willmannca102af2014-08-08 12:14:12 +0200326 }
327
328 /* if the window has stalled, or transfer is complete,
329 * send an unacknowledged block */
Jacob Erlbeck95340242015-03-19 13:22:07 +0100330 if (state_is(GPRS_RLCMAC_FINISHED)) {
331 LOGP(DRLCMACDL, LOGL_DEBUG, "- Restarting at BSN %d, "
332 "because all blocks have been transmitted.\n",
333 m_window.v_a());
334 bts->rlc_restarted();
335 } else if (dl_window_stalled()) {
336 LOGP(DRLCMACDL, LOGL_NOTICE, "- Restarting at BSN %d, "
337 "because all window is stalled.\n",
338 m_window.v_a());
339 bts->rlc_stalled();
Jacob Erlbecke25b5b92015-03-19 14:21:33 +0100340 } else if (have_data()) {
341 /* New blocks may be send */
342 return create_new_bsn(fn, ts);
343 } else if (!m_window.window_empty()) {
344 LOGP(DRLCMACDL, LOGL_DEBUG, "- Restarting at BSN %d, "
345 "because all blocks have been transmitted (FLOW).\n",
346 m_window.v_a());
347 bts->rlc_restarted();
Jacob Erlbeck95340242015-03-19 13:22:07 +0100348 } else {
Jacob Erlbecke25b5b92015-03-19 14:21:33 +0100349 /* Nothing left to send, create dummy LLC commands */
Jacob Erlbeck95340242015-03-19 13:22:07 +0100350 return create_new_bsn(fn, ts);
Daniel Willmannca102af2014-08-08 12:14:12 +0200351 }
352
Jacob Erlbeck95340242015-03-19 13:22:07 +0100353 /* If V(S) == V(A) and finished state, we would have received
354 * acknowledgement of all transmitted block. In this case we
355 * would have transmitted the final block, and received ack
356 * from MS. But in this case we did not receive the final ack
357 * indication from MS. This should never happen if MS works
358 * correctly. */
359 if (m_window.window_empty()) {
360 LOGP(DRLCMACDL, LOGL_DEBUG, "- MS acked all blocks, "
361 "so we re-transmit final block!\n");
362 /* we just send final block again */
363 int16_t index = m_window.v_s_mod(-1);
364 bts->rlc_resent();
365 return create_dl_acked_block(fn, ts, index);
366 }
367
368 /* cycle through all unacked blocks */
369 int resend = m_window.mark_for_resend();
370
371 /* At this point there should be at least one unacked block
372 * to be resent. If not, this is an software error. */
373 if (resend == 0) {
374 LOGP(DRLCMACDL, LOGL_ERROR, "Software error: "
375 "There are no unacknowledged blocks, but V(A) "
376 " != V(S). PLEASE FIX!\n");
377 /* we just send final block again */
378 int16_t index = m_window.v_s_mod(-1);
379 return create_dl_acked_block(fn, ts, index);
380 }
381 goto do_resend;
Daniel Willmannca102af2014-08-08 12:14:12 +0200382}
383
384struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t ts)
385{
386 struct rlc_dl_header *rh;
387 struct rlc_li_field *li;
388 struct msgb *msg;
389 uint8_t *delimiter, *data, *e_pointer;
390 uint16_t space, chunk;
391 gprs_rlc_data *rlc_data;
Daniel Willmannca102af2014-08-08 12:14:12 +0200392 const uint16_t bsn = m_window.v_s();
393
394 LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d\n",
395 m_window.v_s());
396
397#warning "Selection of the CS doesn't belong here"
398 if (cs == 0) {
399 cs = bts_data()->initial_cs_dl;
400 if (cs < 1 || cs > 4)
401 cs = 1;
402 }
403 /* total length of block, including spare bits */
404 const uint8_t block_length = gprs_rlcmac_cs[cs].block_length;
405 /* length of usable data of block, w/o spare bits, inc. MAC */
406 const uint8_t block_data_len = gprs_rlcmac_cs[cs].block_data;
407
408 /* now we still have untransmitted LLC data, so we fill mac block */
409 rlc_data = m_rlc.block(bsn);
410 data = rlc_data->prepare(block_data_len);
411
412 rh = (struct rlc_dl_header *)data;
413 rh->pt = 0; /* Data Block */
414 rh->rrbp = rh->s_p = 0; /* Polling, set later, if required */
415 rh->usf = 7; /* will be set at scheduler */
416 rh->pr = 0; /* FIXME: power reduction */
417 rh->tfi = m_tfi; /* TFI */
418 rh->fbi = 0; /* Final Block Indicator, set late, if true */
419 rh->bsn = bsn; /* Block Sequence Number */
420 rh->e = 0; /* Extension bit, maybe set later */
421 e_pointer = data + 2; /* points to E of current chunk */
422 data += sizeof(*rh);
423 delimiter = data; /* where next length header would be stored */
424 space = block_data_len - sizeof(*rh);
425 while (1) {
Jacob Erlbeckcbb1e702015-03-25 12:21:55 +0100426 if (m_llc.frame_length() == 0) {
427 /* A header will need to by added, so we just need
428 * space-1 octets */
429 m_llc.put_dummy_frame(space - 1);
430
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +0100431 /* The data just drained, store the current fn */
432 if (m_last_dl_drained_fn < 0)
433 m_last_dl_drained_fn = fn;
434
Jacob Erlbeckcbb1e702015-03-25 12:21:55 +0100435 /* It is not clear, when the next real data will
436 * arrive, so request a DL ack/nack now */
437 request_dl_ack();
438
439 LOGP(DRLCMACDL, LOGL_DEBUG,
440 "-- Empty chunk, "
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +0100441 "added LLC dummy command of size %d, "
442 "drained_since=%d\n",
443 m_llc.frame_length(), frames_since_last_drain(fn));
Jacob Erlbeckcbb1e702015-03-25 12:21:55 +0100444 }
445
Daniel Willmannca102af2014-08-08 12:14:12 +0200446 chunk = m_llc.chunk_size();
Jacob Erlbeckcbb1e702015-03-25 12:21:55 +0100447
Daniel Willmannca102af2014-08-08 12:14:12 +0200448 /* if chunk will exceed block limit */
449 if (chunk > space) {
450 LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d "
451 "larger than space (%d) left in block: copy "
452 "only remaining space, and we are done\n",
453 chunk, space);
454 /* block is filled, so there is no extension */
455 *e_pointer |= 0x01;
456 /* fill only space */
457 m_llc.consume(data, space);
458 /* return data block as message */
459 break;
460 }
461 /* if FINAL chunk would fit precisely in space left */
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +0100462 if (chunk == space && llist_empty(&m_llc.queue) && !keep_open(fn))
463 {
Daniel Willmannca102af2014-08-08 12:14:12 +0200464 LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d "
465 "would exactly fit into space (%d): because "
466 "this is a final block, we don't add length "
467 "header, and we are done\n", chunk, space);
468 LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for "
469 "%s that fits precisely in last block: "
470 "len=%d\n", tbf_name(this), m_llc.frame_length());
471 gprs_rlcmac_dl_bw(this, m_llc.frame_length());
472 /* block is filled, so there is no extension */
473 *e_pointer |= 0x01;
474 /* fill space */
475 m_llc.consume(data, space);
476 m_llc.reset();
477 /* final block */
478 rh->fbi = 1; /* we indicate final block */
Jacob Erlbeck7c444152015-03-12 12:08:54 +0100479 request_dl_ack();
Daniel Willmannca102af2014-08-08 12:14:12 +0200480 set_state(GPRS_RLCMAC_FINISHED);
481 /* return data block as message */
482 break;
483 }
484 /* if chunk would fit exactly in space left */
485 if (chunk == space) {
486 LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d "
487 "would exactly fit into space (%d): add length "
488 "header with LI=0, to make frame extend to "
489 "next block, and we are done\n", chunk, space);
490 /* make space for delimiter */
491 if (delimiter != data)
492 memmove(delimiter + 1, delimiter,
493 data - delimiter);
494 data++;
495 space--;
496 /* add LI with 0 length */
497 li = (struct rlc_li_field *)delimiter;
498 li->e = 1; /* not more extension */
499 li->m = 0; /* shall be set to 0, in case of li = 0 */
500 li->li = 0; /* chunk fills the complete space */
501 // no need to set e_pointer nor increase delimiter
502 /* fill only space, which is 1 octet less than chunk */
503 m_llc.consume(data, space);
504 /* return data block as message */
505 break;
506 }
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +0100507
Daniel Willmannca102af2014-08-08 12:14:12 +0200508 LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d is less "
509 "than remaining space (%d): add length header to "
510 "to delimit LLC frame\n", chunk, space);
511 /* the LLC frame chunk ends in this block */
512 /* make space for delimiter */
513 if (delimiter != data)
514 memmove(delimiter + 1, delimiter, data - delimiter);
515 data++;
516 space--;
517 /* add LI to delimit frame */
518 li = (struct rlc_li_field *)delimiter;
519 li->e = 0; /* Extension bit, maybe set later */
520 li->m = 0; /* will be set later, if there is more LLC data */
521 li->li = chunk; /* length of chunk */
522 e_pointer = delimiter; /* points to E of current delimiter */
523 delimiter++;
524 /* copy (rest of) LLC frame to space and reset later */
525 m_llc.consume(data, chunk);
526 data += chunk;
527 space -= chunk;
528 LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for %s"
529 "len=%d\n", tbf_name(this), m_llc.frame_length());
530 gprs_rlcmac_dl_bw(this, m_llc.frame_length());
531 m_llc.reset();
532 /* dequeue next LLC frame, if any */
533 msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
534 if (msg) {
535 LOGP(DRLCMACDL, LOGL_INFO, "- Dequeue next LLC for "
536 "%s (len=%d)\n", tbf_name(this), msg->len);
537 m_llc.put_frame(msg->data, msg->len);
538 bts->llc_frame_sched();
539 msgb_free(msg);
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +0100540 m_last_dl_drained_fn = -1;
Daniel Willmannca102af2014-08-08 12:14:12 +0200541 }
542 /* if we have more data and we have space left */
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +0100543 if (space > 0 && (m_llc.frame_length() || keep_open(fn))) {
Daniel Willmannca102af2014-08-08 12:14:12 +0200544 li->m = 1; /* we indicate more frames to follow */
545 continue;
546 }
547 /* if we don't have more LLC frames */
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +0100548 if (!m_llc.frame_length() && !keep_open(fn)) {
Daniel Willmannca102af2014-08-08 12:14:12 +0200549 LOGP(DRLCMACDL, LOGL_DEBUG, "-- Final block, so we "
550 "done.\n");
551 li->e = 1; /* we cannot extend */
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +0100552
Daniel Willmannca102af2014-08-08 12:14:12 +0200553 rh->fbi = 1; /* we indicate final block */
Jacob Erlbeck7c444152015-03-12 12:08:54 +0100554 request_dl_ack();
Daniel Willmannca102af2014-08-08 12:14:12 +0200555 set_state(GPRS_RLCMAC_FINISHED);
556 break;
557 }
558 /* we have no space left */
559 LOGP(DRLCMACDL, LOGL_DEBUG, "-- No space left, so we are "
560 "done.\n");
561 li->e = 1; /* we cannot extend */
562 break;
563 }
564 LOGP(DRLCMACDL, LOGL_DEBUG, "data block: %s\n",
565 osmo_hexdump(rlc_data->block, block_length));
566#warning "move this up?"
567 rlc_data->len = block_length;
568 /* raise send state and set ack state array */
569 m_window.m_v_b.mark_unacked(bsn);
570 m_window.increment_send();
571
Jacob Erlbeck7c444152015-03-12 12:08:54 +0100572 return create_dl_acked_block(fn, ts, bsn);
573}
574
Daniel Willmannca102af2014-08-08 12:14:12 +0200575struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(
576 const uint32_t fn, const uint8_t ts,
Jacob Erlbeck7c444152015-03-12 12:08:54 +0100577 const int index)
Daniel Willmannca102af2014-08-08 12:14:12 +0200578{
579 uint8_t *data;
580 struct rlc_dl_header *rh;
581 struct msgb *dl_msg;
582 uint8_t len;
Daniel Willmannefd5dbb2014-08-25 16:20:23 +0200583 bool need_poll;
Daniel Willmannca102af2014-08-08 12:14:12 +0200584
585 /* get data and header from current block */
586 data = m_rlc.block(index)->block;
587 len = m_rlc.block(index)->len;
588 rh = (struct rlc_dl_header *)data;
589
Jacob Erlbeck005ee7f2015-03-20 14:53:54 +0100590 /* If the TBF has just started, relate frames_since_last_poll to the
591 * current fn */
592 if (m_last_dl_poll_fn < 0)
593 m_last_dl_poll_fn = fn;
594
Daniel Willmannefd5dbb2014-08-25 16:20:23 +0200595 need_poll = state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK);
Daniel Willmannca102af2014-08-08 12:14:12 +0200596 /* Clear Polling, if still set in history buffer */
597 rh->s_p = 0;
598
599 /* poll after POLL_ACK_AFTER_FRAMES frames, or when final block is tx.
600 */
Jacob Erlbeck7c444152015-03-12 12:08:54 +0100601 if (m_tx_counter >= POLL_ACK_AFTER_FRAMES || m_dl_ack_requested ||
Daniel Willmannefd5dbb2014-08-25 16:20:23 +0200602 need_poll) {
Jacob Erlbeck7c444152015-03-12 12:08:54 +0100603 if (m_dl_ack_requested) {
Daniel Willmannca102af2014-08-08 12:14:12 +0200604 LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack "
Jacob Erlbeck7c444152015-03-12 12:08:54 +0100605 "polling, because is was requested explicitly "
606 "(e.g. first final block sent).\n");
Daniel Willmannefd5dbb2014-08-25 16:20:23 +0200607 } else if (need_poll) {
608 LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack "
Daniel Willmann635d47c2014-09-17 17:58:29 +0200609 "polling, because polling timed out.\n");
Daniel Willmannca102af2014-08-08 12:14:12 +0200610 } else {
611 LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack "
612 "polling, because %d blocks sent.\n",
613 POLL_ACK_AFTER_FRAMES);
614 }
615 /* scheduling not possible, because: */
616 if (poll_state != GPRS_RLCMAC_POLL_NONE)
617 LOGP(DRLCMACDL, LOGL_DEBUG, "Polling is already "
618 "sheduled for %s, so we must wait for "
619 "requesting downlink ack\n", tbf_name(this));
620 else if (control_ts != ts)
621 LOGP(DRLCMACDL, LOGL_DEBUG, "Polling cannot be "
622 "sheduled in this TS %d, waiting for "
623 "TS %d\n", ts, control_ts);
Daniel Willmannca102af2014-08-08 12:14:12 +0200624 else if (bts->sba()->find(trx->trx_no, ts, (fn + 13) % 2715648))
625 LOGP(DRLCMACDL, LOGL_DEBUG, "Polling cannot be "
626 "sheduled, because single block alllocation "
627 "already exists\n");
628 else {
629 LOGP(DRLCMACDL, LOGL_DEBUG, "Polling sheduled in this "
630 "TS %d\n", ts);
631 m_tx_counter = 0;
632 /* start timer whenever we send the final block */
633 if (rh->fbi == 1)
634 tbf_timer_start(this, 3191, bts_data()->t3191, 0);
635
636 /* schedule polling */
637 poll_state = GPRS_RLCMAC_POLL_SCHED;
638 poll_fn = (fn + 13) % 2715648;
639
Daniel Willmannefd5dbb2014-08-25 16:20:23 +0200640 /* Clear poll timeout flag */
641 state_flags &= ~(1 << GPRS_RLCMAC_FLAG_TO_DL_ACK);
642
Jacob Erlbeck7c444152015-03-12 12:08:54 +0100643 /* Clear request flag */
644 m_dl_ack_requested = false;
645
Daniel Willmannca102af2014-08-08 12:14:12 +0200646 /* set polling in header */
647 rh->rrbp = 0; /* N+13 */
648 rh->s_p = 1; /* Polling */
Jacob Erlbeck005ee7f2015-03-20 14:53:54 +0100649
650 m_last_dl_poll_fn = poll_fn;
Daniel Willmannca102af2014-08-08 12:14:12 +0200651 }
652 }
653
654 /* return data block as message */
655 dl_msg = msgb_alloc(len, "rlcmac_dl_data");
656 if (!dl_msg)
657 return NULL;
658
659 /* Increment TX-counter */
660 m_tx_counter++;
661
662 memcpy(msgb_put(dl_msg, len), data, len);
663 bts->rlc_sent();
664
665 return dl_msg;
666}
667
668int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
669{
670 int16_t dist; /* must be signed */
671 uint16_t lost = 0, received = 0;
672 char show_rbb[65];
673 char show_v_b[RLC_MAX_SNS + 1];
674 const uint16_t mod_sns = m_window.mod_sns();
675
676 Decoding::extract_rbb(rbb, show_rbb);
677 /* show received array in debug (bit 64..1) */
678 LOGP(DRLCMACDL, LOGL_DEBUG, "- ack: (BSN=%d)\"%s\""
679 "(BSN=%d) R=ACK I=NACK\n", (ssn - 64) & mod_sns,
680 show_rbb, (ssn - 1) & mod_sns);
681
682 /* apply received array to receive state (SSN-64..SSN-1) */
683 /* calculate distance of ssn from V(S) */
684 dist = (m_window.v_s() - ssn) & mod_sns;
685 /* check if distance is less than distance V(A)..V(S) */
686 if (dist >= m_window.distance()) {
687 /* this might happpen, if the downlink assignment
688 * was not received by ms and the ack refers
689 * to previous TBF
690 * FIXME: we should implement polling for
691 * control ack!*/
692 LOGP(DRLCMACDL, LOGL_NOTICE, "- ack range is out of "
693 "V(A)..V(S) range %s Free TBF!\n", tbf_name(this));
694 return 1; /* indicate to free TBF */
695 }
696
697 m_window.update(bts, show_rbb, ssn,
698 &lost, &received);
699
700 /* report lost and received packets */
701 gprs_rlcmac_received_lost(this, received, lost);
702
703 /* raise V(A), if possible */
704 m_window.raise(m_window.move_window());
705
706 /* show receive state array in debug (V(A)..V(S)-1) */
707 m_window.show_state(show_v_b);
708 LOGP(DRLCMACDL, LOGL_DEBUG, "- V(B): (V(A)=%d)\"%s\""
709 "(V(S)-1=%d) A=Acked N=Nacked U=Unacked "
710 "X=Resend-Unacked I=Invalid\n",
711 m_window.v_a(), show_v_b,
712 m_window.v_s_mod(-1));
713
714 if (state_is(GPRS_RLCMAC_FINISHED) && m_window.window_empty()) {
715 LOGP(DRLCMACDL, LOGL_NOTICE, "Received acknowledge of "
716 "all blocks, but without final ack "
717 "inidcation (don't worry)\n");
718 }
719 return 0;
720}
721
722
723int gprs_rlcmac_dl_tbf::maybe_start_new_window()
724{
725 struct msgb *msg;
726 uint16_t received;
727
728 LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
729 /* range V(A)..V(S)-1 */
730 received = m_window.count_unacked();
731
732 /* report all outstanding packets as received */
733 gprs_rlcmac_received_lost(this, received, 0);
734
735 set_state(GPRS_RLCMAC_WAIT_RELEASE);
736
737 /* check for LLC PDU in the LLC Queue */
738 msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
739 if (!msg) {
740 /* no message, start T3193, change state to RELEASE */
741 LOGP(DRLCMACDL, LOGL_DEBUG, "- No new message, so we release.\n");
742 /* start T3193 */
743 tbf_timer_start(this, 3193,
744 bts_data()->t3193_msec / 1000,
745 (bts_data()->t3193_msec % 1000) * 1000);
746
747 return 0;
748 }
749
750 /* we have more data so we will re-use this tbf */
751 reuse_tbf(msg->data, msg->len);
752 msgb_free(msg);
753 return 0;
754}
755
756int gprs_rlcmac_dl_tbf::rcvd_dl_ack(uint8_t final_ack, uint8_t ssn, uint8_t *rbb)
757{
758 LOGP(DRLCMACDL, LOGL_DEBUG, "%s downlink acknowledge\n", tbf_name(this));
759
760 if (!final_ack)
761 return update_window(ssn, rbb);
762 return maybe_start_new_window();
763}
764
765void gprs_rlcmac_dl_tbf::reuse_tbf(const uint8_t *data, const uint16_t len)
766{
Daniel Willmanne4818152014-08-15 16:52:09 +0200767 uint8_t trx;
Jacob Erlbeck90de3a72015-04-09 19:18:59 +0200768 struct gprs_rlcmac_dl_tbf *new_tbf = NULL;
Daniel Willmanne4818152014-08-15 16:52:09 +0200769 int8_t tfi; /* must be signed */
Daniel Willmanne4818152014-08-15 16:52:09 +0200770 struct msgb *msg;
771
Daniel Willmannca102af2014-08-08 12:14:12 +0200772 bts->tbf_reused();
Daniel Willmanne4818152014-08-15 16:52:09 +0200773
774 tfi = bts->tfi_find_free(GPRS_RLCMAC_DL_TBF, &trx, this->trx->trx_no);
Jacob Erlbeck90de3a72015-04-09 19:18:59 +0200775 if (tfi >= 0)
776 new_tbf = tbf_alloc_dl_tbf(bts->bts_data(), NULL, tfi, trx,
777 ms_class, 0);
778
Daniel Willmanne4818152014-08-15 16:52:09 +0200779 if (!new_tbf) {
780 LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
Jacob Erlbeck90de3a72015-04-09 19:18:59 +0200781 bssgp_tx_llc_discarded(gprs_bssgp_pcu_current_bctx(), m_tlli,
782 1, len);
Daniel Willmanne4818152014-08-15 16:52:09 +0200783 return;
784 }
785
786 new_tbf->m_tlli = m_tlli;
787 new_tbf->m_tlli_valid = m_tlli_valid;
788 new_tbf->ta = ta;
789 new_tbf->assign_imsi(m_imsi);
790
791 /* Copy over all data to the new TBF */
792 new_tbf->m_llc.put_frame(data, len);
Daniel Willmannca102af2014-08-08 12:14:12 +0200793 bts->llc_frame_sched();
794
Daniel Willmanne4818152014-08-15 16:52:09 +0200795 while ((msg = m_llc.dequeue()))
796 new_tbf->m_llc.enqueue(msg);
797
Daniel Willmannca102af2014-08-08 12:14:12 +0200798 /* reset rlc states */
799 m_tx_counter = 0;
800 m_wait_confirm = 0;
801 m_window.reset();
802
Jacob Erlbeck297edf72015-02-26 14:59:52 +0100803 /* mark TLLI as invalid */
804 m_tlli_valid = 0;
805
Daniel Willmannca102af2014-08-08 12:14:12 +0200806 /* keep to flags */
807 state_flags &= GPRS_RLCMAC_FLAG_TO_MASK;
808 state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH);
809
810 update();
811
812 LOGP(DRLCMAC, LOGL_DEBUG, "%s Trigger dowlink assignment on PACCH, "
813 "because another LLC PDU has arrived in between\n",
814 tbf_name(this));
Daniel Willmanne4818152014-08-15 16:52:09 +0200815 bts->trigger_dl_ass(new_tbf, this, NULL);
Daniel Willmannca102af2014-08-08 12:14:12 +0200816}
817
818bool gprs_rlcmac_dl_tbf::dl_window_stalled() const
819{
820 return m_window.window_stalled();
821}
822
Jacob Erlbeckeceb9102015-03-20 14:41:50 +0100823void gprs_rlcmac_dl_tbf::request_dl_ack()
824{
825 m_dl_ack_requested = true;
826}
827
828bool gprs_rlcmac_dl_tbf::need_control_ts() const
829{
830 if (poll_state != GPRS_RLCMAC_POLL_NONE)
831 return false;
832
833 return state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK) ||
834 m_tx_counter >= POLL_ACK_AFTER_FRAMES ||
835 m_dl_ack_requested;
836}
837
838bool gprs_rlcmac_dl_tbf::have_data() const
839{
840 return m_llc.chunk_size() > 0 || !llist_empty(&m_llc.queue);
841}
Jacob Erlbeck005ee7f2015-03-20 14:53:54 +0100842
843int gprs_rlcmac_dl_tbf::frames_since_last_poll(unsigned fn) const
844{
845 unsigned wrapped;
846 if (m_last_dl_poll_fn < 0)
847 return -1;
848
849 wrapped = (fn + 2715648 - m_last_dl_poll_fn) % 2715648;
850 if (wrapped < 2715648/2)
851 return wrapped;
852 else
853 return wrapped - 2715648;
854}
855
Jacob Erlbeck3bed5d12015-03-19 11:22:38 +0100856int gprs_rlcmac_dl_tbf::frames_since_last_drain(unsigned fn) const
857{
858 unsigned wrapped;
859 if (m_last_dl_drained_fn < 0)
860 return -1;
861
862 wrapped = (fn + 2715648 - m_last_dl_drained_fn) % 2715648;
863 if (wrapped < 2715648/2)
864 return wrapped;
865 else
866 return wrapped - 2715648;
867}
868
869bool gprs_rlcmac_dl_tbf::keep_open(unsigned fn) const
870{
871 int keep_time_frames;
872
873 if (bts_data()->dl_tbf_idle_msec <= 0)
874 return false;
875
876 keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec);
877 return frames_since_last_drain(fn) <= keep_time_frames;
878}