blob: b36c61db4395c207d3f3f18eff2c2703301cac05 [file] [log] [blame]
Jacob Erlbecke04e0b02015-05-06 18:30:48 +02001/* gprs_ms.cpp
2 *
3 * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
4 * Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21
22#include "gprs_ms.h"
23
Jacob Erlbecka700dd92015-06-02 16:00:41 +020024#include "bts.h"
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020025#include "tbf.h"
26#include "gprs_debug.h"
27
Jacob Erlbeck8158ea72015-06-04 17:46:33 +020028#include <time.h>
29
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020030extern "C" {
31 #include <osmocom/core/talloc.h>
32 #include <osmocom/core/utils.h>
33}
34
35extern void *tall_pcu_ctx;
36
Jacob Erlbeck8158ea72015-06-04 17:46:33 +020037static int64_t now_msec()
38{
39 struct timespec ts;
40 clock_gettime(CLOCK_MONOTONIC, &ts);
41
42 return int64_t(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
43}
44
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020045struct GprsMsDefaultCallback: public GprsMs::Callback {
46 virtual void ms_idle(class GprsMs *ms) {
47 delete ms;
48 }
49 virtual void ms_active(class GprsMs *) {}
50};
51
52static GprsMsDefaultCallback gprs_default_cb;
53
Jacob Erlbeckd9e10242015-05-28 15:43:53 +020054GprsMs::Guard::Guard(GprsMs *ms) :
55 m_ms(ms ? ms->ref() : NULL)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020056{
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020057}
58
59GprsMs::Guard::~Guard()
60{
61 if (m_ms)
62 m_ms->unref();
63}
64
Jacob Erlbeckb2439bb2015-07-13 14:23:32 +020065bool GprsMs::Guard::is_idle() const
66{
67 if (!m_ms)
68 return true;
69
70 return !m_ms->m_ul_tbf && !m_ms->m_dl_tbf && m_ms->m_ref == 1;
71}
72
Jacob Erlbeckd9e10242015-05-28 15:43:53 +020073void GprsMs::timeout(void *priv_)
74{
75 GprsMs *ms = static_cast<GprsMs *>(priv_);
76
77 LOGP(DRLCMAC, LOGL_INFO, "Timeout for MS object, TLLI = 0x%08x\n",
78 ms->tlli());
79
80 if (ms->m_timer.data) {
81 ms->m_timer.data = NULL;
82 ms->unref();
83 }
84}
85
Jacob Erlbeck17214bb2015-06-02 14:06:12 +020086GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
87 m_bts(bts),
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020088 m_cb(&gprs_default_cb),
89 m_ul_tbf(NULL),
90 m_dl_tbf(NULL),
91 m_tlli(tlli),
Jacob Erlbeck93990462015-05-15 15:50:43 +020092 m_new_ul_tlli(0),
93 m_new_dl_tlli(0),
Jacob Erlbeck9200ce62015-05-22 17:48:04 +020094 m_ta(0),
Jacob Erlbeckbefc7602015-06-02 12:33:30 +020095 m_ms_class(0),
Jacob Erlbecka700dd92015-06-02 16:00:41 +020096 m_current_cs_ul(1),
97 m_current_cs_dl(1),
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020098 m_is_idle(true),
Jacob Erlbeck53670862015-05-12 17:54:33 +020099 m_ref(0),
Jacob Erlbeck25db7c62015-06-11 12:59:01 +0200100 m_list(this),
Jacob Erlbeck04a10862015-06-12 16:01:56 +0200101 m_delay(0),
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200102 m_nack_rate_dl(0),
103 m_reserved_dl_slots(0),
104 m_reserved_ul_slots(0),
105 m_current_trx(NULL)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200106{
107 LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
Jacob Erlbeckb0e5eaf2015-05-21 11:07:16 +0200108
109 m_imsi[0] = 0;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200110 memset(&m_timer, 0, sizeof(m_timer));
111 m_timer.cb = GprsMs::timeout;
Jacob Erlbeck489a2b32015-05-28 19:07:01 +0200112 m_llc_queue.init();
Jacob Erlbecka700dd92015-06-02 16:00:41 +0200113 if (m_bts) {
114 m_current_cs_ul = m_bts->bts_data()->initial_cs_ul;
115 if (m_current_cs_ul < 1)
116 m_current_cs_ul = 1;
117
118 m_current_cs_dl = m_bts->bts_data()->initial_cs_dl;
119 if (m_current_cs_dl < 1)
120 m_current_cs_dl = 1;
121 }
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200122 m_last_cs_not_low = now_msec();
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200123}
124
125GprsMs::~GprsMs()
126{
127 LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", tlli());
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200128
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200129 set_reserved_slots(NULL, 0, 0);
130
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200131 if (osmo_timer_pending(&m_timer))
132 osmo_timer_del(&m_timer);
133
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200134 if (m_ul_tbf) {
135 m_ul_tbf->set_ms(NULL);
136 m_ul_tbf = NULL;
137 }
138
139 if (m_dl_tbf) {
140 m_dl_tbf->set_ms(NULL);
141 m_dl_tbf = NULL;
142 }
Jacob Erlbeck17214bb2015-06-02 14:06:12 +0200143 m_llc_queue.clear(m_bts);
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200144}
145
146void* GprsMs::operator new(size_t size)
147{
148 static void *tall_ms_ctx = NULL;
149 if (!tall_ms_ctx)
150 tall_ms_ctx = talloc_named_const(tall_pcu_ctx, 0, __PRETTY_FUNCTION__);
151
152 return talloc_size(tall_ms_ctx, size);
153}
154
155void GprsMs::operator delete(void* p)
156{
157 talloc_free(p);
158}
159
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200160GprsMs *GprsMs::ref()
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200161{
162 m_ref += 1;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200163 return this;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200164}
165
166void GprsMs::unref()
167{
168 OSMO_ASSERT(m_ref >= 0);
169 m_ref -= 1;
170 if (m_ref == 0)
171 update_status();
172}
173
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200174void GprsMs::start_timer()
175{
176 if (m_delay == 0)
177 return;
178
179 if (!m_timer.data)
180 m_timer.data = ref();
181
182 osmo_timer_schedule(&m_timer, m_delay, 0);
183}
184
185void GprsMs::stop_timer()
186{
187 if (!m_timer.data)
188 return;
189
190 osmo_timer_del(&m_timer);
191 m_timer.data = NULL;
192 unref();
193}
194
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200195void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf)
196{
197 if (tbf->direction == GPRS_RLCMAC_DL_TBF)
198 attach_dl_tbf(static_cast<gprs_rlcmac_dl_tbf *>(tbf));
199 else
200 attach_ul_tbf(static_cast<gprs_rlcmac_ul_tbf *>(tbf));
201}
202
203void GprsMs::attach_ul_tbf(struct gprs_rlcmac_ul_tbf *tbf)
204{
205 if (m_ul_tbf == tbf)
206 return;
207
208 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
209 tlli(), tbf->name());
210
211 Guard guard(this);
212
213 if (m_ul_tbf)
214 detach_tbf(m_ul_tbf);
215
216 m_ul_tbf = tbf;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200217
218 if (tbf)
219 stop_timer();
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200220}
221
222void GprsMs::attach_dl_tbf(struct gprs_rlcmac_dl_tbf *tbf)
223{
224 if (m_dl_tbf == tbf)
225 return;
226
227 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
228 tlli(), tbf->name());
229
230 Guard guard(this);
231
232 if (m_dl_tbf)
233 detach_tbf(m_dl_tbf);
234
235 m_dl_tbf = tbf;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200236
237 if (tbf)
238 stop_timer();
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200239}
240
241void GprsMs::detach_tbf(gprs_rlcmac_tbf *tbf)
242{
243 if (m_ul_tbf && tbf == static_cast<gprs_rlcmac_tbf *>(m_ul_tbf))
244 m_ul_tbf = NULL;
245 else if (m_dl_tbf && tbf == static_cast<gprs_rlcmac_tbf *>(m_dl_tbf))
246 m_dl_tbf = NULL;
247 else
248 return;
249
250 LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n",
251 tlli(), tbf->name());
252
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200253 if (tbf->ms() == this)
254 tbf->set_ms(NULL);
255
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200256 if (!m_dl_tbf && !m_ul_tbf) {
257 set_reserved_slots(NULL, 0, 0);
258
259 if (tlli() != 0)
260 start_timer();
261 }
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200262
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200263 update_status();
264}
265
266void GprsMs::update_status()
267{
268 if (m_ref > 0)
269 return;
270
271 if (is_idle() && !m_is_idle) {
272 m_is_idle = true;
273 m_cb->ms_idle(this);
274 /* this can be deleted by now, do not access it */
275 return;
276 }
277
278 if (!is_idle() && m_is_idle) {
279 m_is_idle = false;
280 m_cb->ms_active(this);
281 }
282}
283
284void GprsMs::set_tlli(uint32_t tlli)
285{
Jacob Erlbeck93990462015-05-15 15:50:43 +0200286 if (tlli == m_tlli || tlli == m_new_ul_tlli)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200287 return;
288
Jacob Erlbeck93990462015-05-15 15:50:43 +0200289 if (tlli != m_new_dl_tlli) {
290 LOGP(DRLCMAC, LOGL_INFO,
291 "Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
292 "not yet confirmed\n",
293 this->tlli(), tlli);
294 m_new_ul_tlli = tlli;
295 return;
296 }
297
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200298 LOGP(DRLCMAC, LOGL_INFO,
Jacob Erlbeck93990462015-05-15 15:50:43 +0200299 "Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
300 "already confirmed partly\n",
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200301 m_tlli, tlli);
302
303 m_tlli = tlli;
Jacob Erlbeck93990462015-05-15 15:50:43 +0200304 m_new_dl_tlli = 0;
305 m_new_ul_tlli = 0;
306}
307
308bool GprsMs::confirm_tlli(uint32_t tlli)
309{
310 if (tlli == m_tlli || tlli == m_new_dl_tlli)
311 return false;
312
313 if (tlli != m_new_ul_tlli) {
314 /* The MS has not sent a message with the new TLLI, which may
315 * happen according to the spec [TODO: add reference]. */
316
317 LOGP(DRLCMAC, LOGL_INFO,
318 "The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
319 "partly confirmed\n", tlli);
320 /* Use the network's idea of TLLI as candidate, this does not
321 * change the result value of tlli() */
322 m_new_dl_tlli = tlli;
323 return false;
324 }
325
326 LOGP(DRLCMAC, LOGL_INFO,
327 "Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
328
329 m_tlli = tlli;
330 m_new_dl_tlli = 0;
331 m_new_ul_tlli = 0;
332
333 return true;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200334}
Jacob Erlbeckb0e5eaf2015-05-21 11:07:16 +0200335
336void GprsMs::set_imsi(const char *imsi)
337{
338 if (!imsi) {
339 LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");
340 return;
341 }
342
343 if (imsi[0] && strlen(imsi) < 3) {
344 LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",
345 imsi);
346 return;
347 }
348
349 if (strcmp(imsi, m_imsi) == 0)
350 return;
351
352 LOGP(DRLCMAC, LOGL_INFO,
353 "Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",
354 tlli(), m_imsi, imsi);
355
356 strncpy(m_imsi, imsi, sizeof(m_imsi));
357 m_imsi[sizeof(m_imsi) - 1] = '\0';
358}
359
Jacob Erlbeck9200ce62015-05-22 17:48:04 +0200360void GprsMs::set_ta(uint8_t ta_)
361{
362 if (ta_ == m_ta)
363 return;
364
365 LOGP(DRLCMAC, LOGL_INFO,
366 "Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
367 tlli(), m_ta, ta_);
368
369 m_ta = ta_;
370}
371
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200372void GprsMs::set_ms_class(uint8_t ms_class_)
373{
374 if (ms_class_ == m_ms_class)
375 return;
376
377 LOGP(DRLCMAC, LOGL_INFO,
378 "Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",
379 tlli(), m_ms_class, ms_class_);
380
381 m_ms_class = ms_class_;
382}
383
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200384void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
385{
386 struct gprs_rlcmac_bts *bts_data;
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200387 int64_t now;
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200388 uint8_t max_cs_dl = 4;
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200389
390 OSMO_ASSERT(m_bts != NULL);
391 bts_data = m_bts->bts_data();
392
393 if (error_rate < 0)
394 return;
395
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200396 now = now_msec();
397
Jacob Erlbeckb33e6752015-06-04 19:04:30 +0200398 if (bts_data->max_cs_dl)
399 max_cs_dl = bts_data->max_cs_dl;
400
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200401 /* TODO: Check for TBF direction */
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200402 /* TODO: Support different CS values for UL and DL */
403
Jacob Erlbeck04a10862015-06-12 16:01:56 +0200404 m_nack_rate_dl = error_rate;
405
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200406 if (error_rate > bts_data->cs_adj_upper_limit) {
407 if (m_current_cs_dl > 1) {
408 m_current_cs_dl -= 1;
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200409 LOGP(DRLCMACDL, LOGL_INFO,
410 "MS (IMSI %s): High error rate %d%%, "
411 "reducing CS level to %d\n",
412 imsi(), error_rate, m_current_cs_dl);
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200413 m_last_cs_not_low = now;
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200414 }
415 } else if (error_rate < bts_data->cs_adj_lower_limit) {
Jacob Erlbeckb33e6752015-06-04 19:04:30 +0200416 if (m_current_cs_dl < max_cs_dl) {
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200417 if (now - m_last_cs_not_low > 1000) {
418 m_current_cs_dl += 1;
Jacob Erlbeckb33e6752015-06-04 19:04:30 +0200419
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200420 LOGP(DRLCMACDL, LOGL_INFO,
421 "MS (IMSI %s): Low error rate %d%%, "
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200422 "increasing DL CS level to %d\n",
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200423 imsi(), error_rate, m_current_cs_dl);
424 m_last_cs_not_low = now;
425 } else {
426 LOGP(DRLCMACDL, LOGL_DEBUG,
427 "MS (IMSI %s): Low error rate %d%%, "
428 "ignored (within blocking period)\n",
429 imsi(), error_rate);
430 }
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200431 }
432 } else {
433 LOGP(DRLCMACDL, LOGL_DEBUG,
434 "MS (IMSI %s): Medium error rate %d%%, ignored\n",
435 imsi(), error_rate);
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200436 m_last_cs_not_low = now;
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200437 }
438}
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200439
440void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
441{
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200442 struct gprs_rlcmac_bts *bts_data;
443 uint8_t max_cs_ul = 4;
Jacob Erlbeck51b11512015-06-11 16:54:50 +0200444 unsigned i;
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200445
446 OSMO_ASSERT(m_bts != NULL);
447 bts_data = m_bts->bts_data();
448
449 if (bts_data->max_cs_ul)
450 max_cs_ul = bts_data->max_cs_ul;
451
452 if (meas->have_link_qual) {
453 int old_link_qual = meas->link_qual;
454 int low = bts_data->cs_lqual_ranges[current_cs_ul()-1].low;
455 int high = bts_data->cs_lqual_ranges[current_cs_ul()-1].high;
456 uint8_t new_cs_ul = m_current_cs_ul;
457
458 if (m_l1_meas.have_link_qual)
459 old_link_qual = m_l1_meas.link_qual;
460
461 if (meas->link_qual < low && old_link_qual < low)
462 new_cs_ul = m_current_cs_ul - 1;
463 else if (meas->link_qual > high && old_link_qual > high &&
464 m_current_cs_ul < max_cs_ul)
465 new_cs_ul = m_current_cs_ul + 1;
466
467 if (m_current_cs_ul != new_cs_ul) {
468 LOGP(DRLCMACDL, LOGL_INFO,
469 "MS (IMSI %s): "
470 "Link quality %ddB (%ddB) left window [%d, %d], "
471 "modifying uplink CS level: %d -> %d\n",
472 imsi(), meas->link_qual, old_link_qual,
473 low, high,
474 m_current_cs_ul, new_cs_ul);
475
476 m_current_cs_ul = new_cs_ul;
477 }
478 }
479
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200480 if (meas->have_rssi)
481 m_l1_meas.set_rssi(meas->rssi);
482 if (meas->have_bto)
483 m_l1_meas.set_bto(meas->bto);
484 if (meas->have_ber)
485 m_l1_meas.set_ber(meas->ber);
486 if (meas->have_link_qual)
487 m_l1_meas.set_link_qual(meas->link_qual);
Jacob Erlbeck51b11512015-06-11 16:54:50 +0200488
489 if (meas->have_ms_rx_qual)
490 m_l1_meas.set_ms_rx_qual(meas->ms_rx_qual);
491 if (meas->have_ms_c_value)
492 m_l1_meas.set_ms_c_value(meas->ms_c_value);
493 if (meas->have_ms_sign_var)
494 m_l1_meas.set_ms_sign_var(meas->ms_sign_var);
495
496 if (meas->have_ms_i_level) {
497 for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
498 if (meas->ts[i].have_ms_i_level)
499 m_l1_meas.set_ms_i_level(i, meas->ts[i].ms_i_level);
500 else
501 m_l1_meas.ts[i].have_ms_i_level = 0;
502 }
503 }
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200504}
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200505
506uint8_t GprsMs::current_cs_dl() const
507{
508 uint8_t cs = m_current_cs_dl;
509 size_t unencoded_octets;
510
511 if (!m_bts)
512 return cs;
513
514 unencoded_octets = m_llc_queue.octets();
515
516 /* If the DL TBF is active, add number of unencoded chunk octets */
517 if (m_dl_tbf)
518 unencoded_octets = m_dl_tbf->m_llc.chunk_size();
519
520 /* There are many unencoded octets, don't reduce */
521 if (unencoded_octets >= m_bts->bts_data()->cs_downgrade_threshold)
522 return cs;
523
524 /* RF conditions are good, don't reduce */
525 if (m_nack_rate_dl < m_bts->bts_data()->cs_adj_lower_limit)
526 return cs;
527
528 /* The throughput would probably be better if the CS level was reduced */
529 cs -= 1;
530
531 /* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
532 if (cs == 2)
533 cs -= 1;
534
535 return cs;
536}
537
Jacob Erlbeck699b8dc2015-06-29 14:05:55 +0200538int GprsMs::first_common_ts() const
539{
540 if (m_dl_tbf)
541 return m_dl_tbf->first_common_ts;
542
543 if (m_ul_tbf)
544 return m_ul_tbf->first_common_ts;
545
546 return -1;
547}
548
Jacob Erlbeck617c7122015-06-30 09:18:30 +0200549uint8_t GprsMs::dl_slots() const
550{
551 uint8_t slots = 0;
552
553 if (m_dl_tbf)
554 slots |= m_dl_tbf->dl_slots();
555
556 if (m_ul_tbf)
557 slots |= m_ul_tbf->dl_slots();
558
559 return slots;
560}
561
562uint8_t GprsMs::ul_slots() const
563{
564 uint8_t slots = 0;
565
566 if (m_dl_tbf)
567 slots |= m_dl_tbf->ul_slots();
568
569 if (m_ul_tbf)
570 slots |= m_ul_tbf->ul_slots();
571
572 return slots;
573}
574
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200575void GprsMs::set_reserved_slots(gprs_rlcmac_trx *trx,
576 uint8_t ul_slots, uint8_t dl_slots)
577{
578 if (m_current_trx) {
579 m_current_trx->unreserve_slots(GPRS_RLCMAC_DL_TBF,
580 m_reserved_dl_slots);
581 m_current_trx->unreserve_slots(GPRS_RLCMAC_UL_TBF,
582 m_reserved_ul_slots);
583 m_reserved_dl_slots = 0;
584 m_reserved_ul_slots = 0;
585 }
586 m_current_trx = trx;
587 if (trx) {
588 m_reserved_dl_slots = dl_slots;
589 m_reserved_ul_slots = ul_slots;
590 m_current_trx->reserve_slots(GPRS_RLCMAC_DL_TBF,
591 m_reserved_dl_slots);
592 m_current_trx->reserve_slots(GPRS_RLCMAC_UL_TBF,
593 m_reserved_ul_slots);
594 }
595}
596
Jacob Erlbeckac89a552015-06-29 14:18:46 +0200597gprs_rlcmac_tbf *GprsMs::tbf(enum gprs_rlcmac_tbf_direction dir) const
598{
599 switch (dir) {
600 case GPRS_RLCMAC_DL_TBF: return m_dl_tbf;
601 case GPRS_RLCMAC_UL_TBF: return m_ul_tbf;
602 }
603
604 return NULL;
605}