blob: 19f2ecb2cbdc488d9f8fd64512c1a240b3343411 [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"
Max1187a772018-01-26 13:31:42 +010023#include <gprs_coding_scheme.h>
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"
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +020027#include "gprs_codel.h"
Jacob Erlbeck7c72aca2016-01-22 17:06:14 +010028#include "pcu_utils.h"
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020029
Jacob Erlbeck8158ea72015-06-04 17:46:33 +020030#include <time.h>
31
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020032extern "C" {
33 #include <osmocom/core/talloc.h>
34 #include <osmocom/core/utils.h>
Max9bbe1602016-07-18 12:50:18 +020035 #include <osmocom/gsm/protocol/gsm_04_08.h>
Max1187a772018-01-26 13:31:42 +010036 #include <osmocom/core/logging.h>
Max136ebcc2019-03-05 14:59:03 +010037 #include "coding_scheme.h"
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020038}
39
Jacob Erlbeck1c3b8992015-08-14 16:01:36 +020040#define GPRS_CODEL_SLOW_INTERVAL_MS 4000
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +020041
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020042extern void *tall_pcu_ctx;
43
Jacob Erlbeck8158ea72015-06-04 17:46:33 +020044static int64_t now_msec()
45{
46 struct timespec ts;
47 clock_gettime(CLOCK_MONOTONIC, &ts);
48
49 return int64_t(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
50}
51
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020052struct GprsMsDefaultCallback: public GprsMs::Callback {
53 virtual void ms_idle(class GprsMs *ms) {
54 delete ms;
55 }
56 virtual void ms_active(class GprsMs *) {}
57};
58
59static GprsMsDefaultCallback gprs_default_cb;
60
Jacob Erlbeckd9e10242015-05-28 15:43:53 +020061GprsMs::Guard::Guard(GprsMs *ms) :
62 m_ms(ms ? ms->ref() : NULL)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020063{
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020064}
65
66GprsMs::Guard::~Guard()
67{
68 if (m_ms)
69 m_ms->unref();
70}
71
Jacob Erlbeckb2439bb2015-07-13 14:23:32 +020072bool GprsMs::Guard::is_idle() const
73{
74 if (!m_ms)
75 return true;
76
77 return !m_ms->m_ul_tbf && !m_ms->m_dl_tbf && m_ms->m_ref == 1;
78}
79
Jacob Erlbeckd9e10242015-05-28 15:43:53 +020080void GprsMs::timeout(void *priv_)
81{
82 GprsMs *ms = static_cast<GprsMs *>(priv_);
83
84 LOGP(DRLCMAC, LOGL_INFO, "Timeout for MS object, TLLI = 0x%08x\n",
85 ms->tlli());
86
87 if (ms->m_timer.data) {
88 ms->m_timer.data = NULL;
89 ms->unref();
90 }
91}
92
Jacob Erlbeck17214bb2015-06-02 14:06:12 +020093GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
94 m_bts(bts),
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020095 m_cb(&gprs_default_cb),
96 m_ul_tbf(NULL),
97 m_dl_tbf(NULL),
98 m_tlli(tlli),
Jacob Erlbeck93990462015-05-15 15:50:43 +020099 m_new_ul_tlli(0),
100 m_new_dl_tlli(0),
Max9bbe1602016-07-18 12:50:18 +0200101 m_ta(GSM48_TA_INVALID),
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200102 m_ms_class(0),
Jacob Erlbeckc3c58042015-09-28 17:55:32 +0200103 m_egprs_ms_class(0),
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200104 m_is_idle(true),
Jacob Erlbeck53670862015-05-12 17:54:33 +0200105 m_ref(0),
Jacob Erlbeck25db7c62015-06-11 12:59:01 +0200106 m_list(this),
Jacob Erlbeck04a10862015-06-12 16:01:56 +0200107 m_delay(0),
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200108 m_nack_rate_dl(0),
109 m_reserved_dl_slots(0),
110 m_reserved_ul_slots(0),
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200111 m_current_trx(NULL),
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100112 m_codel_state(NULL),
Maxa4de02d2019-03-13 16:35:09 +0100113 m_mode(GPRS),
sivasankarida7250a2016-12-16 12:57:18 +0530114 m_dl_ctrl_msg(0)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200115{
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200116 int codel_interval = LLC_CODEL_USE_DEFAULT;
117
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200118 LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
Jacob Erlbeckb0e5eaf2015-05-21 11:07:16 +0200119
120 m_imsi[0] = 0;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200121 memset(&m_timer, 0, sizeof(m_timer));
122 m_timer.cb = GprsMs::timeout;
Jacob Erlbeck489a2b32015-05-28 19:07:01 +0200123 m_llc_queue.init();
Jacob Erlbecka700dd92015-06-02 16:00:41 +0200124
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100125 set_mode(m_mode);
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200126
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100127 if (m_bts)
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200128 codel_interval = m_bts->bts_data()->llc_codel_interval_msec;
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200129
130 if (codel_interval) {
131 if (codel_interval == LLC_CODEL_USE_DEFAULT)
132 codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS;
133 m_codel_state = talloc(this, struct gprs_codel);
134 gprs_codel_init(m_codel_state);
135 gprs_codel_set_interval(m_codel_state, codel_interval);
Jacob Erlbecka700dd92015-06-02 16:00:41 +0200136 }
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200137 m_last_cs_not_low = now_msec();
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200138}
139
140GprsMs::~GprsMs()
141{
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200142 LListHead<gprs_rlcmac_tbf> *pos, *tmp;
143
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200144 LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", tlli());
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200145
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200146 set_reserved_slots(NULL, 0, 0);
147
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200148 if (osmo_timer_pending(&m_timer))
149 osmo_timer_del(&m_timer);
150
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200151 if (m_ul_tbf) {
152 m_ul_tbf->set_ms(NULL);
153 m_ul_tbf = NULL;
154 }
155
156 if (m_dl_tbf) {
157 m_dl_tbf->set_ms(NULL);
158 m_dl_tbf = NULL;
159 }
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200160
161 llist_for_each_safe(pos, tmp, &m_old_tbfs)
162 pos->entry()->set_ms(NULL);
163
Jacob Erlbeck17214bb2015-06-02 14:06:12 +0200164 m_llc_queue.clear(m_bts);
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200165}
166
167void* GprsMs::operator new(size_t size)
168{
169 static void *tall_ms_ctx = NULL;
170 if (!tall_ms_ctx)
171 tall_ms_ctx = talloc_named_const(tall_pcu_ctx, 0, __PRETTY_FUNCTION__);
172
173 return talloc_size(tall_ms_ctx, size);
174}
175
176void GprsMs::operator delete(void* p)
177{
178 talloc_free(p);
179}
180
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200181GprsMs *GprsMs::ref()
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200182{
183 m_ref += 1;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200184 return this;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200185}
186
187void GprsMs::unref()
188{
189 OSMO_ASSERT(m_ref >= 0);
190 m_ref -= 1;
191 if (m_ref == 0)
192 update_status();
193}
194
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200195void GprsMs::start_timer()
196{
197 if (m_delay == 0)
198 return;
199
200 if (!m_timer.data)
201 m_timer.data = ref();
202
203 osmo_timer_schedule(&m_timer, m_delay, 0);
204}
205
206void GprsMs::stop_timer()
207{
208 if (!m_timer.data)
209 return;
210
211 osmo_timer_del(&m_timer);
212 m_timer.data = NULL;
213 unref();
214}
215
Maxa4de02d2019-03-13 16:35:09 +0100216void GprsMs::set_mode(enum mcs_kind mode)
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100217{
218 m_mode = mode;
219
Jacob Erlbeck53bc1862016-01-18 17:23:09 +0100220 if (!m_bts)
221 return;
222
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100223 switch (m_mode) {
Maxa4de02d2019-03-13 16:35:09 +0100224 case GPRS:
Max8a8e0fb2019-03-25 16:32:50 +0100225 if (!mcs_is_gprs(m_current_cs_ul)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100226 m_current_cs_ul = GprsCodingScheme::getGprsByNum(
227 m_bts->bts_data()->initial_cs_ul);
228 if (!m_current_cs_ul.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100229 m_current_cs_ul = CS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100230 }
Max8a8e0fb2019-03-25 16:32:50 +0100231 if (!mcs_is_gprs(m_current_cs_dl)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100232 m_current_cs_dl = GprsCodingScheme::getGprsByNum(
233 m_bts->bts_data()->initial_cs_dl);
234 if (!m_current_cs_dl.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100235 m_current_cs_dl = CS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100236 }
237 break;
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100238
Maxa4de02d2019-03-13 16:35:09 +0100239 case EGPRS_GMSK:
240 case EGPRS:
Max8a8e0fb2019-03-25 16:32:50 +0100241 if (!mcs_is_edge(m_current_cs_ul)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100242 m_current_cs_ul = GprsCodingScheme::getEgprsByNum(
243 m_bts->bts_data()->initial_mcs_ul);
Holger Hans Peter Freytherfd263b02016-03-04 18:24:50 +0100244 if (!m_current_cs_ul.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100245 m_current_cs_ul = MCS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100246 }
Max8a8e0fb2019-03-25 16:32:50 +0100247 if (!mcs_is_edge(m_current_cs_dl)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100248 m_current_cs_dl = GprsCodingScheme::getEgprsByNum(
249 m_bts->bts_data()->initial_mcs_dl);
250 if (!m_current_cs_dl.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100251 m_current_cs_dl = MCS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100252 }
253 break;
254 }
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100255}
256
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200257void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf)
258{
259 if (tbf->direction == GPRS_RLCMAC_DL_TBF)
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100260 attach_dl_tbf(as_dl_tbf(tbf));
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200261 else
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100262 attach_ul_tbf(as_ul_tbf(tbf));
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200263}
264
265void GprsMs::attach_ul_tbf(struct gprs_rlcmac_ul_tbf *tbf)
266{
267 if (m_ul_tbf == tbf)
268 return;
269
270 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
271 tlli(), tbf->name());
272
273 Guard guard(this);
274
275 if (m_ul_tbf)
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200276 llist_add_tail(&m_ul_tbf->ms_list(), &m_old_tbfs);
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200277
278 m_ul_tbf = tbf;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200279
280 if (tbf)
281 stop_timer();
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200282}
283
284void GprsMs::attach_dl_tbf(struct gprs_rlcmac_dl_tbf *tbf)
285{
286 if (m_dl_tbf == tbf)
287 return;
288
289 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
290 tlli(), tbf->name());
291
292 Guard guard(this);
293
294 if (m_dl_tbf)
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200295 llist_add_tail(&m_dl_tbf->ms_list(), &m_old_tbfs);
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200296
297 m_dl_tbf = tbf;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200298
299 if (tbf)
300 stop_timer();
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200301}
302
303void GprsMs::detach_tbf(gprs_rlcmac_tbf *tbf)
304{
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200305 if (tbf == static_cast<gprs_rlcmac_tbf *>(m_ul_tbf)) {
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200306 m_ul_tbf = NULL;
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200307 } else if (tbf == static_cast<gprs_rlcmac_tbf *>(m_dl_tbf)) {
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200308 m_dl_tbf = NULL;
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200309 } else {
310 bool found = false;
311
312 LListHead<gprs_rlcmac_tbf> *pos, *tmp;
313 llist_for_each_safe(pos, tmp, &m_old_tbfs) {
314 if (pos->entry() == tbf) {
315 llist_del(pos);
316 found = true;
317 break;
318 }
319 }
320
321 /* Protect against recursive calls via set_ms() */
322 if (!found)
323 return;
324 }
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200325
326 LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n",
327 tlli(), tbf->name());
328
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200329 if (tbf->ms() == this)
330 tbf->set_ms(NULL);
331
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200332 if (!m_dl_tbf && !m_ul_tbf) {
333 set_reserved_slots(NULL, 0, 0);
334
335 if (tlli() != 0)
336 start_timer();
337 }
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200338
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200339 update_status();
340}
341
342void GprsMs::update_status()
343{
344 if (m_ref > 0)
345 return;
346
347 if (is_idle() && !m_is_idle) {
348 m_is_idle = true;
349 m_cb->ms_idle(this);
350 /* this can be deleted by now, do not access it */
351 return;
352 }
353
354 if (!is_idle() && m_is_idle) {
355 m_is_idle = false;
356 m_cb->ms_active(this);
357 }
358}
359
Jacob Erlbeckac289052015-08-14 12:50:54 +0200360void GprsMs::reset()
361{
362 LOGP(DRLCMAC, LOGL_INFO,
363 "Clearing MS object, TLLI: 0x%08x, IMSI: '%s'\n",
364 tlli(), imsi());
365
366 stop_timer();
367
368 m_tlli = 0;
369 m_new_dl_tlli = 0;
370 m_new_ul_tlli = 0;
371 m_imsi[0] = '\0';
372}
373
Jacob Erlbeck2b349b52015-08-18 11:55:03 +0200374void GprsMs::merge_old_ms(GprsMs *old_ms)
375{
376 if (old_ms == this)
377 return;
378
379 if (strlen(imsi()) == 0 && strlen(old_ms->imsi()) != 0)
380 set_imsi(old_ms->imsi());
381
382 if (!ms_class() && old_ms->ms_class())
383 set_ms_class(old_ms->ms_class());
384
Jacob Erlbecke0b21f42015-08-21 18:30:05 +0200385 m_llc_queue.move_and_merge(&old_ms->m_llc_queue);
386
Jacob Erlbeck2b349b52015-08-18 11:55:03 +0200387 old_ms->reset();
388}
389
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200390void GprsMs::set_tlli(uint32_t tlli)
391{
Jacob Erlbeck93990462015-05-15 15:50:43 +0200392 if (tlli == m_tlli || tlli == m_new_ul_tlli)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200393 return;
394
Jacob Erlbeck93990462015-05-15 15:50:43 +0200395 if (tlli != m_new_dl_tlli) {
396 LOGP(DRLCMAC, LOGL_INFO,
397 "Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
398 "not yet confirmed\n",
399 this->tlli(), tlli);
400 m_new_ul_tlli = tlli;
401 return;
402 }
403
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200404 LOGP(DRLCMAC, LOGL_INFO,
Jacob Erlbeck93990462015-05-15 15:50:43 +0200405 "Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
406 "already confirmed partly\n",
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200407 m_tlli, tlli);
408
409 m_tlli = tlli;
Jacob Erlbeck93990462015-05-15 15:50:43 +0200410 m_new_dl_tlli = 0;
411 m_new_ul_tlli = 0;
412}
413
414bool GprsMs::confirm_tlli(uint32_t tlli)
415{
416 if (tlli == m_tlli || tlli == m_new_dl_tlli)
417 return false;
418
419 if (tlli != m_new_ul_tlli) {
420 /* The MS has not sent a message with the new TLLI, which may
421 * happen according to the spec [TODO: add reference]. */
422
423 LOGP(DRLCMAC, LOGL_INFO,
424 "The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
425 "partly confirmed\n", tlli);
426 /* Use the network's idea of TLLI as candidate, this does not
427 * change the result value of tlli() */
428 m_new_dl_tlli = tlli;
429 return false;
430 }
431
432 LOGP(DRLCMAC, LOGL_INFO,
433 "Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
434
435 m_tlli = tlli;
436 m_new_dl_tlli = 0;
437 m_new_ul_tlli = 0;
438
439 return true;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200440}
Jacob Erlbeckb0e5eaf2015-05-21 11:07:16 +0200441
442void GprsMs::set_imsi(const char *imsi)
443{
444 if (!imsi) {
445 LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");
446 return;
447 }
448
449 if (imsi[0] && strlen(imsi) < 3) {
450 LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",
451 imsi);
452 return;
453 }
454
455 if (strcmp(imsi, m_imsi) == 0)
456 return;
457
458 LOGP(DRLCMAC, LOGL_INFO,
459 "Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",
460 tlli(), m_imsi, imsi);
461
462 strncpy(m_imsi, imsi, sizeof(m_imsi));
463 m_imsi[sizeof(m_imsi) - 1] = '\0';
464}
465
Jacob Erlbeck9200ce62015-05-22 17:48:04 +0200466void GprsMs::set_ta(uint8_t ta_)
467{
468 if (ta_ == m_ta)
469 return;
470
Max9bbe1602016-07-18 12:50:18 +0200471 if (gsm48_ta_is_valid(ta_)) {
472 LOGP(DRLCMAC, LOGL_INFO,
473 "Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
474 tlli(), m_ta, ta_);
475 m_ta = ta_;
476 } else
477 LOGP(DRLCMAC, LOGL_NOTICE,
478 "MS object, TLLI = 0x%08x, invalid TA %d rejected (old "
479 "value %d kept)\n", tlli(), ta_, m_ta);
Jacob Erlbeck9200ce62015-05-22 17:48:04 +0200480}
481
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200482void GprsMs::set_ms_class(uint8_t ms_class_)
483{
484 if (ms_class_ == m_ms_class)
485 return;
486
487 LOGP(DRLCMAC, LOGL_INFO,
488 "Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",
489 tlli(), m_ms_class, ms_class_);
490
491 m_ms_class = ms_class_;
492}
493
Jacob Erlbeckc3c58042015-09-28 17:55:32 +0200494void GprsMs::set_egprs_ms_class(uint8_t ms_class_)
495{
496 if (ms_class_ == m_egprs_ms_class)
497 return;
498
499 LOGP(DRLCMAC, LOGL_INFO,
500 "Modifying MS object, TLLI = 0x%08x, EGPRS MS class %d -> %d\n",
501 tlli(), m_egprs_ms_class, ms_class_);
502
503 m_egprs_ms_class = ms_class_;
504}
505
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200506void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
507{
508 struct gprs_rlcmac_bts *bts_data;
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200509 int64_t now;
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100510 GprsCodingScheme max_cs_dl = this->max_cs_dl();
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200511
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100512 OSMO_ASSERT(max_cs_dl);
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200513 bts_data = m_bts->bts_data();
514
515 if (error_rate < 0)
516 return;
517
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200518 now = now_msec();
519
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200520 /* TODO: Check for TBF direction */
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200521 /* TODO: Support different CS values for UL and DL */
522
Jacob Erlbeck04a10862015-06-12 16:01:56 +0200523 m_nack_rate_dl = error_rate;
524
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200525 if (error_rate > bts_data->cs_adj_upper_limit) {
Max898dddb2019-03-12 15:50:57 +0100526 if (mcs_chan_code(m_current_cs_dl) > 0) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100527 m_current_cs_dl.dec(mode());
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200528 LOGP(DRLCMACDL, LOGL_INFO,
529 "MS (IMSI %s): High error rate %d%%, "
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100530 "reducing CS level to %s\n",
Max136ebcc2019-03-05 14:59:03 +0100531 imsi(), error_rate, mcs_name(m_current_cs_dl));
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200532 m_last_cs_not_low = now;
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200533 }
534 } else if (error_rate < bts_data->cs_adj_lower_limit) {
Jacob Erlbeckb33e6752015-06-04 19:04:30 +0200535 if (m_current_cs_dl < max_cs_dl) {
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200536 if (now - m_last_cs_not_low > 1000) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100537 m_current_cs_dl.inc(mode());
Jacob Erlbeckb33e6752015-06-04 19:04:30 +0200538
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200539 LOGP(DRLCMACDL, LOGL_INFO,
540 "MS (IMSI %s): Low error rate %d%%, "
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100541 "increasing DL CS level to %s\n",
542 imsi(), error_rate,
Max136ebcc2019-03-05 14:59:03 +0100543 mcs_name(m_current_cs_dl));
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200544 m_last_cs_not_low = now;
545 } else {
546 LOGP(DRLCMACDL, LOGL_DEBUG,
547 "MS (IMSI %s): Low error rate %d%%, "
548 "ignored (within blocking period)\n",
549 imsi(), error_rate);
550 }
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200551 }
552 } else {
553 LOGP(DRLCMACDL, LOGL_DEBUG,
554 "MS (IMSI %s): Medium error rate %d%%, ignored\n",
555 imsi(), error_rate);
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200556 m_last_cs_not_low = now;
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200557 }
558}
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200559
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100560GprsCodingScheme GprsMs::max_cs_ul() const
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200561{
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200562 struct gprs_rlcmac_bts *bts_data;
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200563
564 OSMO_ASSERT(m_bts != NULL);
565 bts_data = m_bts->bts_data();
566
Max8a8e0fb2019-03-25 16:32:50 +0100567 if (mcs_is_gprs(m_current_cs_ul)) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100568 if (!bts_data->max_cs_ul)
Maxbea2edb2019-03-06 17:04:59 +0100569 return GprsCodingScheme(CS4);
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200570
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100571 return GprsCodingScheme::getGprsByNum(bts_data->max_cs_ul);
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200572 }
573
Max8a8e0fb2019-03-25 16:32:50 +0100574 if (!mcs_is_edge(m_current_cs_ul))
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100575 return GprsCodingScheme(); /* UNKNOWN */
576
577 if (bts_data->max_mcs_ul)
578 return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_ul);
579 else if (bts_data->max_cs_ul)
580 return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_ul);
581
Maxbea2edb2019-03-06 17:04:59 +0100582 return GprsCodingScheme(MCS4);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100583}
584
Maxbea2edb2019-03-06 17:04:59 +0100585void GprsMs::set_current_cs_dl(CodingScheme scheme)
Aravind Sirsikare8ccafc2016-07-13 11:37:47 +0530586{
587 m_current_cs_dl = scheme;
588}
589
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100590GprsCodingScheme GprsMs::max_cs_dl() const
591{
592 struct gprs_rlcmac_bts *bts_data;
593
594 OSMO_ASSERT(m_bts != NULL);
595 bts_data = m_bts->bts_data();
596
Max8a8e0fb2019-03-25 16:32:50 +0100597 if (mcs_is_gprs(m_current_cs_dl)) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100598 if (!bts_data->max_cs_dl)
Maxbea2edb2019-03-06 17:04:59 +0100599 return GprsCodingScheme(CS4);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100600
601 return GprsCodingScheme::getGprsByNum(bts_data->max_cs_dl);
602 }
603
Max8a8e0fb2019-03-25 16:32:50 +0100604 if (!mcs_is_edge(m_current_cs_dl))
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100605 return GprsCodingScheme(); /* UNKNOWN */
606
607 if (bts_data->max_mcs_dl)
608 return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_dl);
609 else if (bts_data->max_cs_dl)
610 return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_dl);
611
Maxbea2edb2019-03-06 17:04:59 +0100612 return GprsCodingScheme(MCS4);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100613}
614
615void GprsMs::update_cs_ul(const pcu_l1_meas *meas)
616{
617 struct gprs_rlcmac_bts *bts_data;
618 GprsCodingScheme max_cs_ul = this->max_cs_ul();
619
620 int old_link_qual;
621 int low;
622 int high;
623 GprsCodingScheme new_cs_ul = m_current_cs_ul;
Max898dddb2019-03-12 15:50:57 +0100624 uint8_t current_cs = mcs_chan_code(m_current_cs_ul);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100625
626 bts_data = m_bts->bts_data();
627
628 if (!max_cs_ul) {
Minh-Quang Nguyen1f189092017-08-16 09:50:06 -0400629 LOGP(DRLCMACMEAS, LOGL_ERROR,
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100630 "max_cs_ul cannot be derived (current UL CS: %s)\n",
Max136ebcc2019-03-05 14:59:03 +0100631 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100632 return;
633 }
634
Maxfa3085b2019-03-07 11:46:43 +0100635 if (!m_current_cs_ul) {
636 LOGP(DRLCMACMEAS, LOGL_ERROR,
637 "Unable to update UL (M)CS because it's not set: %s\n",
Max136ebcc2019-03-05 14:59:03 +0100638 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100639 return;
Maxfa3085b2019-03-07 11:46:43 +0100640 }
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100641
Maxfa3085b2019-03-07 11:46:43 +0100642 if (!meas->have_link_qual) {
643 LOGP(DRLCMACMEAS, LOGL_ERROR,
644 "Unable to update UL (M)CS %s because we don't have link quality measurements.\n",
Max136ebcc2019-03-05 14:59:03 +0100645 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100646 return;
Maxfa3085b2019-03-07 11:46:43 +0100647 }
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100648
649 old_link_qual = meas->link_qual;
650
Max8a8e0fb2019-03-25 16:32:50 +0100651 if (mcs_is_gprs(m_current_cs_ul)) {
Max898dddb2019-03-12 15:50:57 +0100652 if (current_cs >= MAX_GPRS_CS)
653 current_cs = MAX_GPRS_CS - 1;
654 low = bts_data->cs_lqual_ranges[current_cs].low;
655 high = bts_data->cs_lqual_ranges[current_cs].high;
Max8a8e0fb2019-03-25 16:32:50 +0100656 } else if (mcs_is_edge(m_current_cs_ul)) {
Max898dddb2019-03-12 15:50:57 +0100657 if (current_cs >= MAX_EDGE_MCS)
658 current_cs = MAX_EDGE_MCS - 1;
659 low = bts_data->mcs_lqual_ranges[current_cs].low;
660 high = bts_data->mcs_lqual_ranges[current_cs].high;
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100661 } else {
Maxfa3085b2019-03-07 11:46:43 +0100662 LOGP(DRLCMACMEAS, LOGL_ERROR,
663 "Unable to update UL (M)CS because it's neither GPRS nor EDGE: %s\n",
Max136ebcc2019-03-05 14:59:03 +0100664 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100665 return;
666 }
667
668 if (m_l1_meas.have_link_qual)
669 old_link_qual = m_l1_meas.link_qual;
670
671 if (meas->link_qual < low && old_link_qual < low)
672 new_cs_ul.dec(mode());
673 else if (meas->link_qual > high && old_link_qual > high &&
674 m_current_cs_ul < max_cs_ul)
675 new_cs_ul.inc(mode());
676
677 if (m_current_cs_ul != new_cs_ul) {
Minh-Quang Nguyen1f189092017-08-16 09:50:06 -0400678 LOGP(DRLCMACMEAS, LOGL_INFO,
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100679 "MS (IMSI %s): "
680 "Link quality %ddB (%ddB) left window [%d, %d], "
681 "modifying uplink CS level: %s -> %s\n",
682 imsi(), meas->link_qual, old_link_qual,
683 low, high,
Max136ebcc2019-03-05 14:59:03 +0100684 mcs_name(m_current_cs_ul), mcs_name(new_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100685
686 m_current_cs_ul = new_cs_ul;
687 }
688}
689
690void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
691{
692 unsigned i;
693
694 update_cs_ul(meas);
695
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200696 if (meas->have_rssi)
697 m_l1_meas.set_rssi(meas->rssi);
698 if (meas->have_bto)
699 m_l1_meas.set_bto(meas->bto);
700 if (meas->have_ber)
701 m_l1_meas.set_ber(meas->ber);
702 if (meas->have_link_qual)
703 m_l1_meas.set_link_qual(meas->link_qual);
Jacob Erlbeck51b11512015-06-11 16:54:50 +0200704
705 if (meas->have_ms_rx_qual)
706 m_l1_meas.set_ms_rx_qual(meas->ms_rx_qual);
707 if (meas->have_ms_c_value)
708 m_l1_meas.set_ms_c_value(meas->ms_c_value);
709 if (meas->have_ms_sign_var)
710 m_l1_meas.set_ms_sign_var(meas->ms_sign_var);
711
712 if (meas->have_ms_i_level) {
713 for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
714 if (meas->ts[i].have_ms_i_level)
715 m_l1_meas.set_ms_i_level(i, meas->ts[i].ms_i_level);
716 else
717 m_l1_meas.ts[i].have_ms_i_level = 0;
718 }
719 }
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200720}
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200721
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100722GprsCodingScheme GprsMs::current_cs_dl() const
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200723{
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100724 GprsCodingScheme cs = m_current_cs_dl;
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200725 size_t unencoded_octets;
726
727 if (!m_bts)
728 return cs;
729
730 unencoded_octets = m_llc_queue.octets();
731
732 /* If the DL TBF is active, add number of unencoded chunk octets */
733 if (m_dl_tbf)
Jacob Erlbeck14e26cb2016-02-03 15:26:29 +0100734 unencoded_octets += m_dl_tbf->m_llc.chunk_size();
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200735
736 /* There are many unencoded octets, don't reduce */
737 if (unencoded_octets >= m_bts->bts_data()->cs_downgrade_threshold)
738 return cs;
739
740 /* RF conditions are good, don't reduce */
741 if (m_nack_rate_dl < m_bts->bts_data()->cs_adj_lower_limit)
742 return cs;
743
744 /* The throughput would probably be better if the CS level was reduced */
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100745 cs.dec(mode());
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200746
747 /* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
Maxbea2edb2019-03-06 17:04:59 +0100748 if (cs == GprsCodingScheme(CS2))
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100749 cs.dec(mode());
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200750
751 return cs;
752}
753
Jacob Erlbeck699b8dc2015-06-29 14:05:55 +0200754int GprsMs::first_common_ts() const
755{
756 if (m_dl_tbf)
757 return m_dl_tbf->first_common_ts;
758
759 if (m_ul_tbf)
760 return m_ul_tbf->first_common_ts;
761
762 return -1;
763}
764
Jacob Erlbeck617c7122015-06-30 09:18:30 +0200765uint8_t GprsMs::dl_slots() const
766{
767 uint8_t slots = 0;
768
769 if (m_dl_tbf)
770 slots |= m_dl_tbf->dl_slots();
771
772 if (m_ul_tbf)
773 slots |= m_ul_tbf->dl_slots();
774
775 return slots;
776}
777
778uint8_t GprsMs::ul_slots() const
779{
780 uint8_t slots = 0;
781
782 if (m_dl_tbf)
783 slots |= m_dl_tbf->ul_slots();
784
785 if (m_ul_tbf)
786 slots |= m_ul_tbf->ul_slots();
787
788 return slots;
789}
790
Jacob Erlbeck7c72aca2016-01-22 17:06:14 +0100791uint8_t GprsMs::current_pacch_slots() const
792{
793 uint8_t slots = 0;
794
795 bool is_dl_active = m_dl_tbf && m_dl_tbf->is_tfi_assigned();
796 bool is_ul_active = m_ul_tbf && m_ul_tbf->is_tfi_assigned();
797
798 if (!is_dl_active && !is_ul_active)
799 return 0;
800
801 /* see TS 44.060, 8.1.1.2.2 */
802 if (is_dl_active && !is_ul_active)
803 slots = m_dl_tbf->dl_slots();
804 else if (!is_dl_active && is_ul_active)
805 slots = m_ul_tbf->ul_slots();
806 else
807 slots = m_ul_tbf->ul_slots() & m_dl_tbf->dl_slots();
808
809 /* Assume a multislot class 1 device */
810 /* TODO: For class 2 devices, this could be removed */
811 slots = pcu_lsb(slots);
812
813 return slots;
814}
815
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200816void GprsMs::set_reserved_slots(gprs_rlcmac_trx *trx,
817 uint8_t ul_slots, uint8_t dl_slots)
818{
819 if (m_current_trx) {
820 m_current_trx->unreserve_slots(GPRS_RLCMAC_DL_TBF,
821 m_reserved_dl_slots);
822 m_current_trx->unreserve_slots(GPRS_RLCMAC_UL_TBF,
823 m_reserved_ul_slots);
824 m_reserved_dl_slots = 0;
825 m_reserved_ul_slots = 0;
826 }
827 m_current_trx = trx;
828 if (trx) {
829 m_reserved_dl_slots = dl_slots;
830 m_reserved_ul_slots = ul_slots;
831 m_current_trx->reserve_slots(GPRS_RLCMAC_DL_TBF,
832 m_reserved_dl_slots);
833 m_current_trx->reserve_slots(GPRS_RLCMAC_UL_TBF,
834 m_reserved_ul_slots);
835 }
836}
837
Jacob Erlbeckac89a552015-06-29 14:18:46 +0200838gprs_rlcmac_tbf *GprsMs::tbf(enum gprs_rlcmac_tbf_direction dir) const
839{
840 switch (dir) {
841 case GPRS_RLCMAC_DL_TBF: return m_dl_tbf;
842 case GPRS_RLCMAC_UL_TBF: return m_ul_tbf;
843 }
844
845 return NULL;
846}