blob: f2cd477129b0528145ba4650bcb320cb59c2489a [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 <encoding.h>
26#include <gprs_rlcmac.h>
27#include <gprs_debug.h>
28#include <gprs_bssgp_pcu.h>
29#include <decoding.h>
Jacob Erlbeck20f6fd12015-06-08 11:05:45 +020030#include <pcu_l1_if.h>
Daniel Willmannca102af2014-08-08 12:14:12 +020031
32extern "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 receiving these frames, we send ack/nack. */
41#define SEND_ACK_AFTER_FRAMES 20
42
43extern void *tall_pcu_ctx;
44
45
46/*
47 * Store received block data in LLC message(s) and forward to SGSN
48 * if complete.
49 */
Jacob Erlbeckb3100e12015-12-14 13:36:13 +010050int gprs_rlcmac_ul_tbf::assemble_forward_llc_gprs(const gprs_rlc_data *_data)
Daniel Willmannca102af2014-08-08 12:14:12 +020051{
52 const uint8_t *data = _data->block;
53 uint8_t len = _data->len;
54 const struct rlc_ul_header *rh = (const struct rlc_ul_header *) data;
55 uint8_t e, m;
56 struct rlc_li_field *li;
57 uint8_t frame_offset[16], offset = 0, chunk;
58 int i, frames = 0;
59
60 LOGP(DRLCMACUL, LOGL_DEBUG, "- Assembling frames: (len=%d)\n", len);
61
62 data += 3;
63 len -= 3;
64 e = rh->e; /* if extended */
65 m = 1; /* more frames, that means: the first frame */
66
67 /* Parse frame offsets from length indicator(s), if any. */
68 while (1) {
69 if (frames == (int)sizeof(frame_offset)) {
70 LOGP(DRLCMACUL, LOGL_ERROR, "%s too many frames in "
71 "block\n", tbf_name(this));
72 return -EINVAL;
73 }
74 frame_offset[frames++] = offset;
75 LOGP(DRLCMACUL, LOGL_DEBUG, "-- Frame %d starts at offset "
76 "%d\n", frames, offset);
77 if (!len)
78 break;
79 /* M == 0 and E == 0 is not allowed in this version. */
80 if (!m && !e) {
81 LOGP(DRLCMACUL, LOGL_NOTICE, "%s UL DATA "
82 "ignored, because M='0' and E='0'.\n",
83 tbf_name(this));
84 return 0;
85 }
86 /* no more frames in this segment */
87 if (e) {
88 break;
89 }
90 /* There is a new frame and an LI that delimits it. */
91 if (m) {
92 li = (struct rlc_li_field *)data;
93 LOGP(DRLCMACUL, LOGL_DEBUG, "-- Delimiter len=%d\n",
94 li->li);
95 /* Special case: LI == 0
96 * If the last segment would fit precisely into the
97 * rest of the RLC MAC block, there would be no way
98 * to delimit that this segment ends and is not
99 * continued in the next block.
100 * The special LI (0) is used to force the segment to
101 * extend into the next block, so it is delimited there.
102 * This LI must be skipped. Also it is the last LI.
103 */
104 if (li->li == 0) {
105 data++;
106 len--;
107 m = 1; /* M is ignored, we know there is more */
108 break; /* handle E as '1', so we break! */
109 }
110 e = li->e;
111 m = li->m;
112 offset += li->li;
113 data++;
114 len--;
115 continue;
116 }
117 }
118 if (!m) {
119 LOGP(DRLCMACUL, LOGL_DEBUG, "- Last frame carries spare "
120 "data\n");
121 }
122
123 LOGP(DRLCMACUL, LOGL_DEBUG, "- Data length after length fields: %d\n",
124 len);
125 /* TLLI */
126 if (rh->ti) {
127 if (len < 4) {
128 LOGP(DRLCMACUL, LOGL_NOTICE, "%s UL DATA TLLI out of "
129 "frame border\n", tbf_name(this));
130 return -EINVAL;
131 }
132 data += 4;
133 len -= 4;
134 LOGP(DRLCMACUL, LOGL_DEBUG, "- Length after skipping TLLI: "
135 "%d\n", len);
136 }
137
138 /* PFI */
139 if (rh->pi) {
140 LOGP(DRLCMACUL, LOGL_ERROR, "ERROR: PFI not supported, "
141 "please disable in SYSTEM INFORMATION\n");
142 if (len < 1) {
143 LOGP(DRLCMACUL, LOGL_NOTICE, "%s UL DATA PFI out of "
144 "frame border\n", tbf_name(this));
145 return -EINVAL;
146 }
147 data++;
148 len--;
149 LOGP(DRLCMACUL, LOGL_DEBUG, "- Length after skipping PFI: "
150 "%d\n", len);
151 }
152
153 /* Now we have:
154 * - a list of frames offsets: frame_offset[]
155 * - number of frames: i
156 * - m == 0: Last frame carries spare data (end of TBF).
157 */
158
159 /* Check if last offset would exceed frame. */
160 if (offset > len) {
161 LOGP(DRLCMACUL, LOGL_NOTICE, "%s UL DATA ignored, "
162 "because LI delimits data that exceeds block size.\n",
163 tbf_name(this));
164 return -EINVAL;
165 }
166
167 /* create LLC frames */
168 for (i = 0; i < frames; i++) {
169 /* last frame ? */
170 if (i == frames - 1) {
171 /* no more data in last frame */
172 if (!m)
173 break;
174 /* data until end of frame */
175 chunk = len - frame_offset[i];
176 } else {
177 /* data until next frame */
178 chunk = frame_offset[i + 1] - frame_offset[i];
179 }
180 if (!m_llc.fits_in_current_frame(chunk)) {
181 LOGP(DRLCMACUL, LOGL_NOTICE, "%s LLC frame exceeds "
182 "maximum size %u.\n", tbf_name(this),
183 m_llc.remaining_space());
184 chunk = m_llc.remaining_space();
185 }
186 m_llc.append_frame(data + frame_offset[i], chunk);
187 m_llc.consume(chunk);
188 /* not last frame. */
189 if (i != frames - 1) {
190 /* send frame to SGSN */
191 LOGP(DRLCMACUL, LOGL_INFO, "%s complete UL frame len=%d\n",
192 tbf_name(this) , m_llc.frame_length());
193 snd_ul_ud();
194 m_llc.reset();
195 /* also check if CV==0, because the frame may fill up the
196 * block precisely, then it is also complete. normally the
197 * frame would be extended into the next block with a 0-length
198 * delimiter added to this block. */
199 } else if (rh->cv == 0) {
200 /* send frame to SGSN */
201 LOGP(DRLCMACUL, LOGL_INFO, "%s complete UL frame "
202 "that fits precisely in last block: "
203 "len=%d\n", tbf_name(this), m_llc.frame_length());
204 snd_ul_ud();
205 m_llc.reset();
206 }
207 }
208
209 return 0;
210}
211
Jacob Erlbeckb3100e12015-12-14 13:36:13 +0100212/*
213 * Store received block data in LLC message(s) and forward to SGSN
214 * if complete.
215 */
216int gprs_rlcmac_ul_tbf::assemble_forward_llc(const gprs_rlc_data *_data)
217{
218 const uint8_t *data = _data->block;
219 uint8_t len = _data->len;
220 const struct gprs_rlc_ul_data_block_info *rdbi = &_data->block_info;
221 GprsCodingScheme cs = _data->cs;
222
223 Decoding::RlcData frames[16], *frame;
224 int i, num_frames = 0;
225 uint32_t dummy_tlli;
226
227 LOGP(DRLCMACUL, LOGL_DEBUG, "- Assembling frames: (len=%d)\n", len);
228
229 num_frames = Decoding::rlc_data_from_ul_data(
230 rdbi, cs, data, &(frames[0]), sizeof(frames),
231 &dummy_tlli);
232
233 /* create LLC frames */
234 for (i = 0; i < num_frames; i++) {
235 frame = frames + i;
236
237 LOGP(DRLCMACUL, LOGL_DEBUG, "-- Frame %d starts at offset %d, "
238 "length=%d, is_complete=%d\n",
239 i + 1, frame->offset, frame->length, frame->is_complete);
240
241 m_llc.append_frame(data + frame->offset, frame->length);
242 m_llc.consume(frame->length);
243
244 if (frame->is_complete) {
245 /* send frame to SGSN */
246 LOGP(DRLCMACUL, LOGL_INFO, "%s complete UL frame len=%d\n",
247 tbf_name(this) , m_llc.frame_length());
248 snd_ul_ud();
249 m_llc.reset();
250 }
251 }
252
253 return 0;
254}
255
Daniel Willmannca102af2014-08-08 12:14:12 +0200256
257struct msgb *gprs_rlcmac_ul_tbf::create_ul_ack(uint32_t fn)
258{
259 int final = (state_is(GPRS_RLCMAC_FINISHED));
260 struct msgb *msg;
261
262 if (final) {
263 if (poll_state != GPRS_RLCMAC_POLL_NONE) {
264 LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
265 "sheduled for %s, so we must wait for "
266 "final uplink ack...\n", tbf_name(this));
267 return NULL;
268 }
269 if (bts->sba()->find(trx->trx_no, control_ts, (fn + 13) % 2715648)) {
270 LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
271 "scheduled for single block allocation...\n");
272 return NULL;
273 }
274 }
275
276 msg = msgb_alloc(23, "rlcmac_ul_ack");
277 if (!msg)
278 return NULL;
279 bitvec *ack_vec = bitvec_alloc(23);
280 if (!ack_vec) {
281 msgb_free(msg);
282 return NULL;
283 }
284 bitvec_unhex(ack_vec,
285 "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
286 RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
287 Encoding::write_packet_uplink_ack(bts_data(), mac_control_block, this, final);
288 encode_gsm_rlcmac_downlink(ack_vec, mac_control_block);
289 bitvec_pack(ack_vec, msgb_put(msg, 23));
290 bitvec_free(ack_vec);
291 talloc_free(mac_control_block);
292
293 /* now we must set this flag, so we are allowed to assign downlink
294 * TBF on PACCH. it is only allowed when TLLI is acknowledged. */
295 m_contention_resolution_done = 1;
296
297 if (final) {
298 poll_state = GPRS_RLCMAC_POLL_SCHED;
299 poll_fn = (fn + 13) % 2715648;
300 /* waiting for final acknowledge */
301 ul_ack_state = GPRS_RLCMAC_UL_ACK_WAIT_ACK;
302 m_final_ack_sent = 1;
303 } else
304 ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE;
305
306 return msg;
307}
308
Jacob Erlbeckb3100e12015-12-14 13:36:13 +0100309int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
310 const struct gprs_rlc_ul_header_egprs *rlc,
311 uint8_t *data, uint8_t len, struct pcu_l1_meas *meas)
312{
313 int8_t rssi = meas->have_rssi ? meas->rssi : 0;
314
315 const uint16_t mod_sns = m_window.mod_sns();
316 const uint16_t ws = m_window.ws();
317
318 this->state_flags |= (1 << GPRS_RLCMAC_FLAG_UL_DATA);
319
320 LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA TFI=%d received (V(Q)=%d .. "
321 "V(R)=%d)\n", rlc->tfi, this->m_window.v_q(),
322 this->m_window.v_r());
323
324 /* process RSSI */
325 gprs_rlcmac_rssi(this, rssi);
326
327 /* store measurement values */
328 if (ms())
329 ms()->update_l1_meas(meas);
330
331 uint32_t new_tlli = 0;
332 unsigned int block_idx;
333
334 /* restart T3169 */
335 tbf_timer_start(this, 3169, bts_data()->t3169, 0);
336
337 /* Increment RX-counter */
338 this->m_rx_counter++;
339
340 /* Loop over num_blocks */
341 for (block_idx = 0; block_idx < rlc->num_data_blocks; block_idx++) {
342 int num_chunks;
343 uint8_t *rlc_data;
344 const struct gprs_rlc_ul_data_block_info *rdbi =
345 &rlc->block_info[block_idx];
346 bool need_rlc_data = false;
347 struct gprs_rlc_data *block;
348
349 LOGP(DRLCMACUL, LOGL_DEBUG,
350 "%s: Got %s RLC data block: "
351 "CV=%d, BSN=%d, SPB=%d, "
352 "PI=%d, E=%d, TI=%d, bitoffs=%d\n",
353 name(), rlc->cs.name(),
354 rdbi->cv, rdbi->bsn, rdbi->spb,
355 rdbi->pi, rdbi->e, rdbi->ti,
356 rlc->data_offs_bits[block_idx]);
357
358 /* Check whether the block needs to be decoded */
359
360 if (!m_window.is_in_window(rdbi->bsn)) {
361 LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d out of window "
362 "%d..%d (it's normal)\n", rdbi->bsn,
363 m_window.v_q(),
364 (m_window.v_q() + ws - 1) & mod_sns);
365 } else if (m_window.is_received(rdbi->bsn)) {
366 LOGP(DRLCMACUL, LOGL_DEBUG,
367 "- BSN %d already received\n", rdbi->bsn);
368 } else {
369 need_rlc_data = true;
370 }
371
372 if (!is_tlli_valid()) {
373 if (!rdbi->ti) {
374 LOGP(DRLCMACUL, LOGL_NOTICE,
375 "%s: Missing TLLI within UL DATA.\n",
376 name());
377 continue;
378 }
379 need_rlc_data = true;
380 }
381
382 if (!need_rlc_data)
383 continue;
384
385 /* Store block and meta info to BSN buffer */
386
387 LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d storing in window (%d..%d)\n",
388 rdbi->bsn, m_window.v_q(),
389 (m_window.v_q() + ws - 1) & mod_sns);
390 block = m_rlc.block(rdbi->bsn);
391 block->block_info = *rdbi;
392 block->cs = rlc->cs;
393 OSMO_ASSERT(rdbi->data_len < sizeof(block->block));
394 rlc_data = &(block->block[0]);
395 /* TODO: Handle SPB != 0 -> Set length to 2*len, add offset if
396 * 2nd part. Note that resegmentation is currently disabled
397 * within the UL assignment.
398 */
399 if (rdbi->spb) {
400 LOGP(DRLCMACUL, LOGL_NOTICE,
401 "Got SPB != 0 but resegmentation has been "
402 "disabled, skipping %s data block with BSN %d, "
403 "TFI=%d.\n", rlc->cs.name(), rdbi->bsn,
404 rlc->tfi);
405 continue;
406 }
407
408 block->len =
409 Decoding::rlc_copy_to_aligned_buffer(rlc, block_idx, data,
410 rlc_data);
411
412
413 /* TODO: Handle SPB != 0 -> set state to partly received
414 * (upper/lower) and continue with the loop, unless the other
415 * part is already present.
416 */
417
418 /* Get/Handle TLLI */
419 if (rdbi->ti) {
420 num_chunks = Decoding::rlc_data_from_ul_data(
421 rdbi, rlc->cs, rlc_data, NULL, 0, &new_tlli);
422
423 if (num_chunks < 0) {
424 bts->decode_error();
425 LOGP(DRLCMACUL, LOGL_NOTICE,
426 "Failed to decode TLLI of %s UL DATA "
427 "TFI=%d.\n", rlc->cs.name(), rlc->tfi);
428 m_window.invalidate_bsn(rdbi->bsn);
429 continue;
430 }
431 if (!this->is_tlli_valid()) {
432 if (!new_tlli) {
433 LOGP(DRLCMACUL, LOGL_NOTICE,
434 "%s: TLLI = 0 within UL DATA.\n",
435 name());
436 m_window.invalidate_bsn(rdbi->bsn);
437 continue;
438 }
439 LOGP(DRLCMACUL, LOGL_INFO,
440 "Decoded premier TLLI=0x%08x of "
441 "UL DATA TFI=%d.\n", tlli(), rlc->tfi);
442 set_tlli_from_ul(new_tlli);
443 } else if (new_tlli && new_tlli != tlli()) {
444 LOGP(DRLCMACUL, LOGL_NOTICE, "TLLI mismatch on UL "
445 "DATA TFI=%d. (Ignoring due to contention "
446 "resolution)\n", rlc->tfi);
447 m_window.invalidate_bsn(rdbi->bsn);
448 continue;
449 }
450 }
451
452 m_window.receive_bsn(rdbi->bsn);
453 }
454
455 /* Raise V(Q) if possible, and retrieve LLC frames from blocks.
456 * This is looped until there is a gap (non received block) or
457 * the window is empty.*/
458 const uint16_t v_q_beg = m_window.v_q();
459 const uint16_t count = m_window.raise_v_q();
460
461 /* Retrieve LLC frames from blocks that are ready */
462 for (uint16_t i = 0; i < count; ++i) {
463 uint16_t index = (v_q_beg + i) & mod_sns;
464 assemble_forward_llc(m_rlc.block(index));
465 }
466
467 /* Check CV of last frame in buffer */
468 if (this->state_is(GPRS_RLCMAC_FLOW) /* still in flow state */
469 && this->m_window.v_q() == this->m_window.v_r()) { /* if complete */
470 struct gprs_rlc_data *block =
471 m_rlc.block((m_window.v_r() - 1) & mod_sns);
472 const struct gprs_rlc_ul_data_block_info *rdbi =
473 &block->block_info;
474
475 LOGP(DRLCMACUL, LOGL_DEBUG, "- No gaps in received block, "
476 "last block: BSN=%d CV=%d\n", rdbi->bsn,
477 rdbi->cv);
478 if (rdbi->cv == 0) {
479 LOGP(DRLCMACUL, LOGL_DEBUG, "- Finished with UL "
480 "TBF\n");
481 set_state(GPRS_RLCMAC_FINISHED);
482 /* Reset N3103 counter. */
483 this->m_n3103 = 0;
484 }
485 }
486
487 /* If TLLI is included or if we received half of the window, we send
488 * an ack/nack */
489 maybe_schedule_uplink_acknack(rlc);
490
491 return 0;
492}
493
Jacob Erlbeck3b802e32015-12-07 15:50:35 +0100494int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged_gprs(const uint8_t *data,
Jacob Erlbeck20f6fd12015-06-08 11:05:45 +0200495 size_t len, struct pcu_l1_meas *meas)
Daniel Willmannca102af2014-08-08 12:14:12 +0200496{
497 struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
498 int rc;
Jacob Erlbeck20f6fd12015-06-08 11:05:45 +0200499 int8_t rssi = meas->have_rssi ? meas->rssi : 0;
Daniel Willmannca102af2014-08-08 12:14:12 +0200500
501 const uint16_t mod_sns = m_window.mod_sns();
502 const uint16_t ws = m_window.ws();
503
504 this->state_flags |= (1 << GPRS_RLCMAC_FLAG_UL_DATA);
505
506 LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA TFI=%d received (V(Q)=%d .. "
507 "V(R)=%d)\n", rh->tfi, this->m_window.v_q(),
508 this->m_window.v_r());
509
510 /* process RSSI */
511 gprs_rlcmac_rssi(this, rssi);
512
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200513 /* store measurement values */
514 if (ms())
515 ms()->update_l1_meas(meas);
516
Daniel Willmannca102af2014-08-08 12:14:12 +0200517 /* get TLLI */
518 if (!this->is_tlli_valid()) {
519 if (!extract_tlli(data, len))
520 return 0;
521 /* already have TLLI, but we stille get another one */
522 } else if (rh->ti) {
523 uint32_t tlli;
524 rc = Decoding::tlli_from_ul_data(data, len, &tlli);
525 if (rc) {
526 LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI "
527 "of UL DATA TFI=%d.\n", rh->tfi);
528 return 0;
529 }
530 if (tlli != this->tlli()) {
531 LOGP(DRLCMACUL, LOGL_NOTICE, "TLLI mismatch on UL "
532 "DATA TFI=%d. (Ignoring due to contention "
533 "resolution)\n", rh->tfi);
534 return 0;
535 }
536 }
537
538 /* restart T3169 */
539 tbf_timer_start(this, 3169, bts_data()->t3169, 0);
540
541 /* Increment RX-counter */
542 this->m_rx_counter++;
543
544 if (!m_window.is_in_window(rh->bsn)) {
545 LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d out of window "
546 "%d..%d (it's normal)\n", rh->bsn,
547 m_window.v_q(),
548 (m_window.v_q() + ws - 1) & mod_sns);
549 maybe_schedule_uplink_acknack(rh);
550 return 0;
551 }
552
553 /* Write block to buffer and set receive state array. */
554 m_rlc.block(rh->bsn)->put_data(data, len);
555 LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d storing in window (%d..%d)\n",
556 rh->bsn, m_window.v_q(),
557 (m_window.v_q() + ws - 1) & mod_sns);
558
559 /* Raise V(Q) if possible, and retrieve LLC frames from blocks.
560 * This is looped until there is a gap (non received block) or
561 * the window is empty.*/
562 const uint16_t v_q_beg = m_window.v_q();
563
Jacob Erlbeckd87e1d62015-12-14 11:43:04 +0100564 m_window.receive_bsn(rh->bsn);
565 const uint16_t count = m_window.raise_v_q();
Daniel Willmannca102af2014-08-08 12:14:12 +0200566
567 /* Retrieve LLC frames from blocks that are ready */
568 for (uint16_t i = 0; i < count; ++i) {
569 uint16_t index = (v_q_beg + i) & mod_sns;
Jacob Erlbeckb3100e12015-12-14 13:36:13 +0100570 assemble_forward_llc_gprs(m_rlc.block(index));
Daniel Willmannca102af2014-08-08 12:14:12 +0200571 }
572
573 /* Check CV of last frame in buffer */
574 if (this->state_is(GPRS_RLCMAC_FLOW) /* still in flow state */
575 && this->m_window.v_q() == this->m_window.v_r()) { /* if complete */
576 struct rlc_ul_header *last_rh = (struct rlc_ul_header *)
577 m_rlc.block((m_window.v_r() - 1) & mod_sns)->block;
578 LOGP(DRLCMACUL, LOGL_DEBUG, "- No gaps in received block, "
579 "last block: BSN=%d CV=%d\n", last_rh->bsn,
580 last_rh->cv);
581 if (last_rh->cv == 0) {
582 LOGP(DRLCMACUL, LOGL_DEBUG, "- Finished with UL "
583 "TBF\n");
584 set_state(GPRS_RLCMAC_FINISHED);
585 /* Reset N3103 counter. */
586 this->m_n3103 = 0;
587 }
588 }
589
590 /* If TLLI is included or if we received half of the window, we send
591 * an ack/nack */
592 maybe_schedule_uplink_acknack(rh);
593
594 return 0;
595}
596
Jacob Erlbeckb3100e12015-12-14 13:36:13 +0100597void gprs_rlcmac_ul_tbf::maybe_schedule_uplink_acknack(
598 const gprs_rlc_ul_header_egprs *rlc)
599{
600 bool have_ti = rlc->block_info[0].ti ||
601 (rlc->num_data_blocks > 1 && rlc->block_info[1].ti);
602
603 if (rlc->si || have_ti || state_is(GPRS_RLCMAC_FINISHED) ||
604 (m_rx_counter % SEND_ACK_AFTER_FRAMES) == 0)
605 {
606 if (rlc->si) {
607 LOGP(DRLCMACUL, LOGL_NOTICE, "- Scheduling Ack/Nack, "
608 "because MS is stalled.\n");
609 }
610 if (have_ti) {
611 LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
612 "because TLLI is included.\n");
613 }
614 if (state_is(GPRS_RLCMAC_FINISHED)) {
615 LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
616 "because last block has CV==0.\n");
617 }
618 if ((m_rx_counter % SEND_ACK_AFTER_FRAMES) == 0) {
619 LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
620 "because %d frames received.\n",
621 SEND_ACK_AFTER_FRAMES);
622 }
623 if (ul_ack_state == GPRS_RLCMAC_UL_ACK_NONE) {
624 /* trigger sending at next RTS */
625 ul_ack_state = GPRS_RLCMAC_UL_ACK_SEND_ACK;
626 } else {
627 /* already triggered */
628 LOGP(DRLCMACUL, LOGL_DEBUG, "- Sending Ack/Nack is "
629 "already triggered, don't schedule!\n");
630 }
631 }
632}
633
Daniel Willmannca102af2014-08-08 12:14:12 +0200634void gprs_rlcmac_ul_tbf::maybe_schedule_uplink_acknack(const rlc_ul_header *rh)
635{
636 if (rh->si || rh->ti || state_is(GPRS_RLCMAC_FINISHED)
637 || (m_rx_counter % SEND_ACK_AFTER_FRAMES) == 0) {
638 if (rh->si) {
639 LOGP(DRLCMACUL, LOGL_NOTICE, "- Scheduling Ack/Nack, "
640 "because MS is stalled.\n");
641 }
642 if (rh->ti) {
643 LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
644 "because TLLI is included.\n");
645 }
646 if (state_is(GPRS_RLCMAC_FINISHED)) {
647 LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
648 "because last block has CV==0.\n");
649 }
650 if ((m_rx_counter % SEND_ACK_AFTER_FRAMES) == 0) {
651 LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
652 "because %d frames received.\n",
653 SEND_ACK_AFTER_FRAMES);
654 }
655 if (ul_ack_state == GPRS_RLCMAC_UL_ACK_NONE) {
656 /* trigger sending at next RTS */
657 ul_ack_state = GPRS_RLCMAC_UL_ACK_SEND_ACK;
658 } else {
659 /* already triggered */
660 LOGP(DRLCMACUL, LOGL_DEBUG, "- Sending Ack/Nack is "
661 "already triggered, don't schedule!\n");
662 }
663 }
664}
665
666/* Send Uplink unit-data to SGSN. */
667int gprs_rlcmac_ul_tbf::snd_ul_ud()
668{
669 uint8_t qos_profile[3];
670 struct msgb *llc_pdu;
671 unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + m_llc.frame_length();
672 struct bssgp_bvc_ctx *bctx = gprs_bssgp_pcu_current_bctx();
673
674 LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] %s len=%d\n", tbf_name(this), m_llc.frame_length());
675 if (!bctx) {
676 LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
677 m_llc.reset_frame_space();
678 return -EIO;
679 }
680
681 llc_pdu = msgb_alloc_headroom(msg_len, msg_len,"llc_pdu");
682 uint8_t *buf = msgb_push(llc_pdu, TL16V_GROSS_LEN(sizeof(uint8_t)*m_llc.frame_length()));
683 tl16v_put(buf, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*m_llc.frame_length(), m_llc.frame);
684 qos_profile[0] = QOS_PROFILE >> 16;
685 qos_profile[1] = QOS_PROFILE >> 8;
686 qos_profile[2] = QOS_PROFILE;
687 bssgp_tx_ul_ud(bctx, tlli(), qos_profile, llc_pdu);
688
689 m_llc.reset_frame_space();
690 return 0;
691}
692