blob: 8074cb4a3da0863dae411beb8b8695824f34fad8 [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"
Pau Espin Pedrol9d1cdb12019-09-25 17:47:02 +020026#include "tbf_ul.h"
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020027#include "gprs_debug.h"
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +020028#include "gprs_codel.h"
Jacob Erlbeck7c72aca2016-01-22 17:06:14 +010029#include "pcu_utils.h"
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020030
Jacob Erlbeck8158ea72015-06-04 17:46:33 +020031#include <time.h>
32
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020033extern "C" {
34 #include <osmocom/core/talloc.h>
35 #include <osmocom/core/utils.h>
Max9bbe1602016-07-18 12:50:18 +020036 #include <osmocom/gsm/protocol/gsm_04_08.h>
Max1187a772018-01-26 13:31:42 +010037 #include <osmocom/core/logging.h>
Max136ebcc2019-03-05 14:59:03 +010038 #include "coding_scheme.h"
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020039}
40
Jacob Erlbeck1c3b8992015-08-14 16:01:36 +020041#define GPRS_CODEL_SLOW_INTERVAL_MS 4000
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +020042
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020043extern void *tall_pcu_ctx;
44
Jacob Erlbeck8158ea72015-06-04 17:46:33 +020045static int64_t now_msec()
46{
47 struct timespec ts;
48 clock_gettime(CLOCK_MONOTONIC, &ts);
49
50 return int64_t(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
51}
52
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020053struct GprsMsDefaultCallback: public GprsMs::Callback {
54 virtual void ms_idle(class GprsMs *ms) {
55 delete ms;
56 }
57 virtual void ms_active(class GprsMs *) {}
58};
59
60static GprsMsDefaultCallback gprs_default_cb;
61
Jacob Erlbeckd9e10242015-05-28 15:43:53 +020062GprsMs::Guard::Guard(GprsMs *ms) :
63 m_ms(ms ? ms->ref() : NULL)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020064{
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020065}
66
67GprsMs::Guard::~Guard()
68{
69 if (m_ms)
70 m_ms->unref();
71}
72
Jacob Erlbeckb2439bb2015-07-13 14:23:32 +020073bool GprsMs::Guard::is_idle() const
74{
75 if (!m_ms)
76 return true;
77
78 return !m_ms->m_ul_tbf && !m_ms->m_dl_tbf && m_ms->m_ref == 1;
79}
80
Jacob Erlbeckd9e10242015-05-28 15:43:53 +020081void GprsMs::timeout(void *priv_)
82{
83 GprsMs *ms = static_cast<GprsMs *>(priv_);
84
85 LOGP(DRLCMAC, LOGL_INFO, "Timeout for MS object, TLLI = 0x%08x\n",
86 ms->tlli());
87
88 if (ms->m_timer.data) {
89 ms->m_timer.data = NULL;
90 ms->unref();
91 }
92}
93
Jacob Erlbeck17214bb2015-06-02 14:06:12 +020094GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
95 m_bts(bts),
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020096 m_cb(&gprs_default_cb),
97 m_ul_tbf(NULL),
98 m_dl_tbf(NULL),
99 m_tlli(tlli),
Jacob Erlbeck93990462015-05-15 15:50:43 +0200100 m_new_ul_tlli(0),
101 m_new_dl_tlli(0),
Max9bbe1602016-07-18 12:50:18 +0200102 m_ta(GSM48_TA_INVALID),
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200103 m_ms_class(0),
Jacob Erlbeckc3c58042015-09-28 17:55:32 +0200104 m_egprs_ms_class(0),
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200105 m_is_idle(true),
Jacob Erlbeck53670862015-05-12 17:54:33 +0200106 m_ref(0),
Jacob Erlbeck25db7c62015-06-11 12:59:01 +0200107 m_list(this),
Jacob Erlbeck04a10862015-06-12 16:01:56 +0200108 m_delay(0),
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200109 m_nack_rate_dl(0),
110 m_reserved_dl_slots(0),
111 m_reserved_ul_slots(0),
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200112 m_current_trx(NULL),
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100113 m_codel_state(NULL),
Maxa4de02d2019-03-13 16:35:09 +0100114 m_mode(GPRS),
sivasankarida7250a2016-12-16 12:57:18 +0530115 m_dl_ctrl_msg(0)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200116{
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200117 int codel_interval = LLC_CODEL_USE_DEFAULT;
118
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200119 LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
Jacob Erlbeckb0e5eaf2015-05-21 11:07:16 +0200120
121 m_imsi[0] = 0;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200122 memset(&m_timer, 0, sizeof(m_timer));
123 m_timer.cb = GprsMs::timeout;
Jacob Erlbeck489a2b32015-05-28 19:07:01 +0200124 m_llc_queue.init();
Jacob Erlbecka700dd92015-06-02 16:00:41 +0200125
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100126 set_mode(m_mode);
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200127
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100128 if (m_bts)
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200129 codel_interval = m_bts->bts_data()->llc_codel_interval_msec;
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200130
131 if (codel_interval) {
132 if (codel_interval == LLC_CODEL_USE_DEFAULT)
133 codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS;
134 m_codel_state = talloc(this, struct gprs_codel);
135 gprs_codel_init(m_codel_state);
136 gprs_codel_set_interval(m_codel_state, codel_interval);
Jacob Erlbecka700dd92015-06-02 16:00:41 +0200137 }
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200138 m_last_cs_not_low = now_msec();
Oliver Smithcfb63212019-09-05 17:13:33 +0200139 app_info_pending = false;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200140}
141
142GprsMs::~GprsMs()
143{
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200144 LListHead<gprs_rlcmac_tbf> *pos, *tmp;
145
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200146 LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", tlli());
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200147
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200148 set_reserved_slots(NULL, 0, 0);
149
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200150 if (osmo_timer_pending(&m_timer))
151 osmo_timer_del(&m_timer);
152
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200153 if (m_ul_tbf) {
154 m_ul_tbf->set_ms(NULL);
155 m_ul_tbf = NULL;
156 }
157
158 if (m_dl_tbf) {
159 m_dl_tbf->set_ms(NULL);
160 m_dl_tbf = NULL;
161 }
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200162
163 llist_for_each_safe(pos, tmp, &m_old_tbfs)
164 pos->entry()->set_ms(NULL);
165
Jacob Erlbeck17214bb2015-06-02 14:06:12 +0200166 m_llc_queue.clear(m_bts);
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200167}
168
169void* GprsMs::operator new(size_t size)
170{
171 static void *tall_ms_ctx = NULL;
172 if (!tall_ms_ctx)
173 tall_ms_ctx = talloc_named_const(tall_pcu_ctx, 0, __PRETTY_FUNCTION__);
174
175 return talloc_size(tall_ms_ctx, size);
176}
177
178void GprsMs::operator delete(void* p)
179{
180 talloc_free(p);
181}
182
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200183GprsMs *GprsMs::ref()
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200184{
185 m_ref += 1;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200186 return this;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200187}
188
189void GprsMs::unref()
190{
191 OSMO_ASSERT(m_ref >= 0);
192 m_ref -= 1;
193 if (m_ref == 0)
194 update_status();
195}
196
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200197void GprsMs::start_timer()
198{
199 if (m_delay == 0)
200 return;
201
202 if (!m_timer.data)
203 m_timer.data = ref();
204
205 osmo_timer_schedule(&m_timer, m_delay, 0);
206}
207
208void GprsMs::stop_timer()
209{
210 if (!m_timer.data)
211 return;
212
213 osmo_timer_del(&m_timer);
214 m_timer.data = NULL;
215 unref();
216}
217
Maxa4de02d2019-03-13 16:35:09 +0100218void GprsMs::set_mode(enum mcs_kind mode)
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100219{
220 m_mode = mode;
221
Jacob Erlbeck53bc1862016-01-18 17:23:09 +0100222 if (!m_bts)
223 return;
224
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100225 switch (m_mode) {
Maxa4de02d2019-03-13 16:35:09 +0100226 case GPRS:
Max8a8e0fb2019-03-25 16:32:50 +0100227 if (!mcs_is_gprs(m_current_cs_ul)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100228 m_current_cs_ul = GprsCodingScheme::getGprsByNum(
229 m_bts->bts_data()->initial_cs_ul);
230 if (!m_current_cs_ul.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100231 m_current_cs_ul = CS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100232 }
Max8a8e0fb2019-03-25 16:32:50 +0100233 if (!mcs_is_gprs(m_current_cs_dl)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100234 m_current_cs_dl = GprsCodingScheme::getGprsByNum(
235 m_bts->bts_data()->initial_cs_dl);
236 if (!m_current_cs_dl.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100237 m_current_cs_dl = CS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100238 }
239 break;
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100240
Maxa4de02d2019-03-13 16:35:09 +0100241 case EGPRS_GMSK:
242 case EGPRS:
Max8a8e0fb2019-03-25 16:32:50 +0100243 if (!mcs_is_edge(m_current_cs_ul)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100244 m_current_cs_ul = GprsCodingScheme::getEgprsByNum(
245 m_bts->bts_data()->initial_mcs_ul);
Holger Hans Peter Freytherfd263b02016-03-04 18:24:50 +0100246 if (!m_current_cs_ul.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100247 m_current_cs_ul = MCS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100248 }
Max8a8e0fb2019-03-25 16:32:50 +0100249 if (!mcs_is_edge(m_current_cs_dl)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100250 m_current_cs_dl = GprsCodingScheme::getEgprsByNum(
251 m_bts->bts_data()->initial_mcs_dl);
252 if (!m_current_cs_dl.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100253 m_current_cs_dl = MCS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100254 }
255 break;
256 }
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100257}
258
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200259void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf)
260{
261 if (tbf->direction == GPRS_RLCMAC_DL_TBF)
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100262 attach_dl_tbf(as_dl_tbf(tbf));
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200263 else
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100264 attach_ul_tbf(as_ul_tbf(tbf));
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200265}
266
267void GprsMs::attach_ul_tbf(struct gprs_rlcmac_ul_tbf *tbf)
268{
269 if (m_ul_tbf == tbf)
270 return;
271
272 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
273 tlli(), tbf->name());
274
275 Guard guard(this);
276
277 if (m_ul_tbf)
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200278 llist_add_tail(&m_ul_tbf->ms_list(), &m_old_tbfs);
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200279
280 m_ul_tbf = tbf;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200281
282 if (tbf)
283 stop_timer();
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200284}
285
286void GprsMs::attach_dl_tbf(struct gprs_rlcmac_dl_tbf *tbf)
287{
288 if (m_dl_tbf == tbf)
289 return;
290
291 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
292 tlli(), tbf->name());
293
294 Guard guard(this);
295
296 if (m_dl_tbf)
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200297 llist_add_tail(&m_dl_tbf->ms_list(), &m_old_tbfs);
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200298
299 m_dl_tbf = tbf;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200300
301 if (tbf)
302 stop_timer();
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200303}
304
305void GprsMs::detach_tbf(gprs_rlcmac_tbf *tbf)
306{
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200307 if (tbf == static_cast<gprs_rlcmac_tbf *>(m_ul_tbf)) {
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200308 m_ul_tbf = NULL;
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200309 } else if (tbf == static_cast<gprs_rlcmac_tbf *>(m_dl_tbf)) {
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200310 m_dl_tbf = NULL;
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200311 } else {
312 bool found = false;
313
314 LListHead<gprs_rlcmac_tbf> *pos, *tmp;
315 llist_for_each_safe(pos, tmp, &m_old_tbfs) {
316 if (pos->entry() == tbf) {
317 llist_del(pos);
318 found = true;
319 break;
320 }
321 }
322
323 /* Protect against recursive calls via set_ms() */
324 if (!found)
325 return;
326 }
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200327
328 LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n",
329 tlli(), tbf->name());
330
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200331 if (tbf->ms() == this)
332 tbf->set_ms(NULL);
333
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200334 if (!m_dl_tbf && !m_ul_tbf) {
335 set_reserved_slots(NULL, 0, 0);
336
337 if (tlli() != 0)
338 start_timer();
339 }
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200340
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200341 update_status();
342}
343
344void GprsMs::update_status()
345{
346 if (m_ref > 0)
347 return;
348
349 if (is_idle() && !m_is_idle) {
350 m_is_idle = true;
351 m_cb->ms_idle(this);
352 /* this can be deleted by now, do not access it */
353 return;
354 }
355
356 if (!is_idle() && m_is_idle) {
357 m_is_idle = false;
358 m_cb->ms_active(this);
359 }
360}
361
Jacob Erlbeckac289052015-08-14 12:50:54 +0200362void GprsMs::reset()
363{
364 LOGP(DRLCMAC, LOGL_INFO,
365 "Clearing MS object, TLLI: 0x%08x, IMSI: '%s'\n",
366 tlli(), imsi());
367
368 stop_timer();
369
370 m_tlli = 0;
371 m_new_dl_tlli = 0;
372 m_new_ul_tlli = 0;
373 m_imsi[0] = '\0';
374}
375
Jacob Erlbeck2b349b52015-08-18 11:55:03 +0200376void GprsMs::merge_old_ms(GprsMs *old_ms)
377{
378 if (old_ms == this)
379 return;
380
381 if (strlen(imsi()) == 0 && strlen(old_ms->imsi()) != 0)
382 set_imsi(old_ms->imsi());
383
384 if (!ms_class() && old_ms->ms_class())
385 set_ms_class(old_ms->ms_class());
386
Jacob Erlbecke0b21f42015-08-21 18:30:05 +0200387 m_llc_queue.move_and_merge(&old_ms->m_llc_queue);
388
Jacob Erlbeck2b349b52015-08-18 11:55:03 +0200389 old_ms->reset();
390}
391
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200392void GprsMs::set_tlli(uint32_t tlli)
393{
Jacob Erlbeck93990462015-05-15 15:50:43 +0200394 if (tlli == m_tlli || tlli == m_new_ul_tlli)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200395 return;
396
Jacob Erlbeck93990462015-05-15 15:50:43 +0200397 if (tlli != m_new_dl_tlli) {
398 LOGP(DRLCMAC, LOGL_INFO,
399 "Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
400 "not yet confirmed\n",
401 this->tlli(), tlli);
402 m_new_ul_tlli = tlli;
403 return;
404 }
405
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200406 LOGP(DRLCMAC, LOGL_INFO,
Jacob Erlbeck93990462015-05-15 15:50:43 +0200407 "Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
408 "already confirmed partly\n",
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200409 m_tlli, tlli);
410
411 m_tlli = tlli;
Jacob Erlbeck93990462015-05-15 15:50:43 +0200412 m_new_dl_tlli = 0;
413 m_new_ul_tlli = 0;
414}
415
416bool GprsMs::confirm_tlli(uint32_t tlli)
417{
418 if (tlli == m_tlli || tlli == m_new_dl_tlli)
419 return false;
420
421 if (tlli != m_new_ul_tlli) {
422 /* The MS has not sent a message with the new TLLI, which may
423 * happen according to the spec [TODO: add reference]. */
424
425 LOGP(DRLCMAC, LOGL_INFO,
426 "The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
427 "partly confirmed\n", tlli);
428 /* Use the network's idea of TLLI as candidate, this does not
429 * change the result value of tlli() */
430 m_new_dl_tlli = tlli;
431 return false;
432 }
433
434 LOGP(DRLCMAC, LOGL_INFO,
435 "Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
436
437 m_tlli = tlli;
438 m_new_dl_tlli = 0;
439 m_new_ul_tlli = 0;
440
441 return true;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200442}
Jacob Erlbeckb0e5eaf2015-05-21 11:07:16 +0200443
444void GprsMs::set_imsi(const char *imsi)
445{
446 if (!imsi) {
447 LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");
448 return;
449 }
450
451 if (imsi[0] && strlen(imsi) < 3) {
452 LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",
453 imsi);
454 return;
455 }
456
457 if (strcmp(imsi, m_imsi) == 0)
458 return;
459
460 LOGP(DRLCMAC, LOGL_INFO,
461 "Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",
462 tlli(), m_imsi, imsi);
463
464 strncpy(m_imsi, imsi, sizeof(m_imsi));
465 m_imsi[sizeof(m_imsi) - 1] = '\0';
466}
467
Jacob Erlbeck9200ce62015-05-22 17:48:04 +0200468void GprsMs::set_ta(uint8_t ta_)
469{
470 if (ta_ == m_ta)
471 return;
472
Max9bbe1602016-07-18 12:50:18 +0200473 if (gsm48_ta_is_valid(ta_)) {
474 LOGP(DRLCMAC, LOGL_INFO,
475 "Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
476 tlli(), m_ta, ta_);
477 m_ta = ta_;
478 } else
479 LOGP(DRLCMAC, LOGL_NOTICE,
480 "MS object, TLLI = 0x%08x, invalid TA %d rejected (old "
481 "value %d kept)\n", tlli(), ta_, m_ta);
Jacob Erlbeck9200ce62015-05-22 17:48:04 +0200482}
483
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200484void GprsMs::set_ms_class(uint8_t ms_class_)
485{
486 if (ms_class_ == m_ms_class)
487 return;
488
489 LOGP(DRLCMAC, LOGL_INFO,
490 "Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",
491 tlli(), m_ms_class, ms_class_);
492
493 m_ms_class = ms_class_;
494}
495
Jacob Erlbeckc3c58042015-09-28 17:55:32 +0200496void GprsMs::set_egprs_ms_class(uint8_t ms_class_)
497{
498 if (ms_class_ == m_egprs_ms_class)
499 return;
500
501 LOGP(DRLCMAC, LOGL_INFO,
502 "Modifying MS object, TLLI = 0x%08x, EGPRS MS class %d -> %d\n",
503 tlli(), m_egprs_ms_class, ms_class_);
504
505 m_egprs_ms_class = ms_class_;
506}
507
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200508void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
509{
510 struct gprs_rlcmac_bts *bts_data;
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200511 int64_t now;
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100512 GprsCodingScheme max_cs_dl = this->max_cs_dl();
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200513
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100514 OSMO_ASSERT(max_cs_dl);
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200515 bts_data = m_bts->bts_data();
516
517 if (error_rate < 0)
518 return;
519
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200520 now = now_msec();
521
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200522 /* TODO: Check for TBF direction */
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200523 /* TODO: Support different CS values for UL and DL */
524
Jacob Erlbeck04a10862015-06-12 16:01:56 +0200525 m_nack_rate_dl = error_rate;
526
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200527 if (error_rate > bts_data->cs_adj_upper_limit) {
Max898dddb2019-03-12 15:50:57 +0100528 if (mcs_chan_code(m_current_cs_dl) > 0) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100529 m_current_cs_dl.dec(mode());
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200530 LOGP(DRLCMACDL, LOGL_INFO,
531 "MS (IMSI %s): High error rate %d%%, "
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100532 "reducing CS level to %s\n",
Max136ebcc2019-03-05 14:59:03 +0100533 imsi(), error_rate, mcs_name(m_current_cs_dl));
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200534 m_last_cs_not_low = now;
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200535 }
536 } else if (error_rate < bts_data->cs_adj_lower_limit) {
Jacob Erlbeckb33e6752015-06-04 19:04:30 +0200537 if (m_current_cs_dl < max_cs_dl) {
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200538 if (now - m_last_cs_not_low > 1000) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100539 m_current_cs_dl.inc(mode());
Jacob Erlbeckb33e6752015-06-04 19:04:30 +0200540
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200541 LOGP(DRLCMACDL, LOGL_INFO,
542 "MS (IMSI %s): Low error rate %d%%, "
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100543 "increasing DL CS level to %s\n",
544 imsi(), error_rate,
Max136ebcc2019-03-05 14:59:03 +0100545 mcs_name(m_current_cs_dl));
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200546 m_last_cs_not_low = now;
547 } else {
548 LOGP(DRLCMACDL, LOGL_DEBUG,
549 "MS (IMSI %s): Low error rate %d%%, "
550 "ignored (within blocking period)\n",
551 imsi(), error_rate);
552 }
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200553 }
554 } else {
555 LOGP(DRLCMACDL, LOGL_DEBUG,
556 "MS (IMSI %s): Medium error rate %d%%, ignored\n",
557 imsi(), error_rate);
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200558 m_last_cs_not_low = now;
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200559 }
560}
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200561
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100562GprsCodingScheme GprsMs::max_cs_ul() const
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200563{
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200564 struct gprs_rlcmac_bts *bts_data;
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200565
566 OSMO_ASSERT(m_bts != NULL);
567 bts_data = m_bts->bts_data();
568
Max8a8e0fb2019-03-25 16:32:50 +0100569 if (mcs_is_gprs(m_current_cs_ul)) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100570 if (!bts_data->max_cs_ul)
Maxbea2edb2019-03-06 17:04:59 +0100571 return GprsCodingScheme(CS4);
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200572
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100573 return GprsCodingScheme::getGprsByNum(bts_data->max_cs_ul);
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200574 }
575
Max8a8e0fb2019-03-25 16:32:50 +0100576 if (!mcs_is_edge(m_current_cs_ul))
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100577 return GprsCodingScheme(); /* UNKNOWN */
578
579 if (bts_data->max_mcs_ul)
580 return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_ul);
581 else if (bts_data->max_cs_ul)
582 return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_ul);
583
Maxbea2edb2019-03-06 17:04:59 +0100584 return GprsCodingScheme(MCS4);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100585}
586
Maxbea2edb2019-03-06 17:04:59 +0100587void GprsMs::set_current_cs_dl(CodingScheme scheme)
Aravind Sirsikare8ccafc2016-07-13 11:37:47 +0530588{
589 m_current_cs_dl = scheme;
590}
591
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100592GprsCodingScheme GprsMs::max_cs_dl() const
593{
594 struct gprs_rlcmac_bts *bts_data;
595
596 OSMO_ASSERT(m_bts != NULL);
597 bts_data = m_bts->bts_data();
598
Max8a8e0fb2019-03-25 16:32:50 +0100599 if (mcs_is_gprs(m_current_cs_dl)) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100600 if (!bts_data->max_cs_dl)
Maxbea2edb2019-03-06 17:04:59 +0100601 return GprsCodingScheme(CS4);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100602
603 return GprsCodingScheme::getGprsByNum(bts_data->max_cs_dl);
604 }
605
Max8a8e0fb2019-03-25 16:32:50 +0100606 if (!mcs_is_edge(m_current_cs_dl))
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100607 return GprsCodingScheme(); /* UNKNOWN */
608
609 if (bts_data->max_mcs_dl)
610 return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_dl);
611 else if (bts_data->max_cs_dl)
612 return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_dl);
613
Maxbea2edb2019-03-06 17:04:59 +0100614 return GprsCodingScheme(MCS4);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100615}
616
617void GprsMs::update_cs_ul(const pcu_l1_meas *meas)
618{
619 struct gprs_rlcmac_bts *bts_data;
620 GprsCodingScheme max_cs_ul = this->max_cs_ul();
621
622 int old_link_qual;
623 int low;
624 int high;
625 GprsCodingScheme new_cs_ul = m_current_cs_ul;
Max898dddb2019-03-12 15:50:57 +0100626 uint8_t current_cs = mcs_chan_code(m_current_cs_ul);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100627
628 bts_data = m_bts->bts_data();
629
630 if (!max_cs_ul) {
Minh-Quang Nguyen1f189092017-08-16 09:50:06 -0400631 LOGP(DRLCMACMEAS, LOGL_ERROR,
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100632 "max_cs_ul cannot be derived (current UL CS: %s)\n",
Max136ebcc2019-03-05 14:59:03 +0100633 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100634 return;
635 }
636
Maxfa3085b2019-03-07 11:46:43 +0100637 if (!m_current_cs_ul) {
638 LOGP(DRLCMACMEAS, LOGL_ERROR,
639 "Unable to update UL (M)CS because it's not set: %s\n",
Max136ebcc2019-03-05 14:59:03 +0100640 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100641 return;
Maxfa3085b2019-03-07 11:46:43 +0100642 }
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100643
Maxfa3085b2019-03-07 11:46:43 +0100644 if (!meas->have_link_qual) {
645 LOGP(DRLCMACMEAS, LOGL_ERROR,
646 "Unable to update UL (M)CS %s because we don't have link quality measurements.\n",
Max136ebcc2019-03-05 14:59:03 +0100647 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100648 return;
Maxfa3085b2019-03-07 11:46:43 +0100649 }
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100650
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
Vadim Yanitskiyfd734de2019-11-08 05:37:18 +0700668 /* To avoid rapid changes of the coding scheme, we also take
669 * the old link quality value into account (if present). */
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100670 if (m_l1_meas.have_link_qual)
671 old_link_qual = m_l1_meas.link_qual;
Vadim Yanitskiyfd734de2019-11-08 05:37:18 +0700672 else
673 old_link_qual = meas->link_qual;
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100674
675 if (meas->link_qual < low && old_link_qual < low)
676 new_cs_ul.dec(mode());
677 else if (meas->link_qual > high && old_link_qual > high &&
678 m_current_cs_ul < max_cs_ul)
679 new_cs_ul.inc(mode());
680
681 if (m_current_cs_ul != new_cs_ul) {
Minh-Quang Nguyen1f189092017-08-16 09:50:06 -0400682 LOGP(DRLCMACMEAS, LOGL_INFO,
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100683 "MS (IMSI %s): "
Vadim Yanitskiyfd734de2019-11-08 05:37:18 +0700684 "Link quality %ddB (old %ddB) left window [%d, %d], "
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100685 "modifying uplink CS level: %s -> %s\n",
686 imsi(), meas->link_qual, old_link_qual,
687 low, high,
Max136ebcc2019-03-05 14:59:03 +0100688 mcs_name(m_current_cs_ul), mcs_name(new_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100689
690 m_current_cs_ul = new_cs_ul;
691 }
692}
693
694void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
695{
696 unsigned i;
697
698 update_cs_ul(meas);
699
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200700 if (meas->have_rssi)
701 m_l1_meas.set_rssi(meas->rssi);
702 if (meas->have_bto)
703 m_l1_meas.set_bto(meas->bto);
704 if (meas->have_ber)
705 m_l1_meas.set_ber(meas->ber);
706 if (meas->have_link_qual)
707 m_l1_meas.set_link_qual(meas->link_qual);
Jacob Erlbeck51b11512015-06-11 16:54:50 +0200708
709 if (meas->have_ms_rx_qual)
710 m_l1_meas.set_ms_rx_qual(meas->ms_rx_qual);
711 if (meas->have_ms_c_value)
712 m_l1_meas.set_ms_c_value(meas->ms_c_value);
713 if (meas->have_ms_sign_var)
714 m_l1_meas.set_ms_sign_var(meas->ms_sign_var);
715
716 if (meas->have_ms_i_level) {
717 for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
718 if (meas->ts[i].have_ms_i_level)
719 m_l1_meas.set_ms_i_level(i, meas->ts[i].ms_i_level);
720 else
721 m_l1_meas.ts[i].have_ms_i_level = 0;
722 }
723 }
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200724}
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200725
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100726GprsCodingScheme GprsMs::current_cs_dl() const
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200727{
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100728 GprsCodingScheme cs = m_current_cs_dl;
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200729 size_t unencoded_octets;
730
731 if (!m_bts)
732 return cs;
733
734 unencoded_octets = m_llc_queue.octets();
735
736 /* If the DL TBF is active, add number of unencoded chunk octets */
737 if (m_dl_tbf)
Jacob Erlbeck14e26cb2016-02-03 15:26:29 +0100738 unencoded_octets += m_dl_tbf->m_llc.chunk_size();
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200739
740 /* There are many unencoded octets, don't reduce */
741 if (unencoded_octets >= m_bts->bts_data()->cs_downgrade_threshold)
742 return cs;
743
744 /* RF conditions are good, don't reduce */
745 if (m_nack_rate_dl < m_bts->bts_data()->cs_adj_lower_limit)
746 return cs;
747
748 /* The throughput would probably be better if the CS level was reduced */
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100749 cs.dec(mode());
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200750
751 /* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
Maxbea2edb2019-03-06 17:04:59 +0100752 if (cs == GprsCodingScheme(CS2))
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100753 cs.dec(mode());
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200754
755 return cs;
756}
757
Jacob Erlbeck699b8dc2015-06-29 14:05:55 +0200758int GprsMs::first_common_ts() const
759{
760 if (m_dl_tbf)
761 return m_dl_tbf->first_common_ts;
762
763 if (m_ul_tbf)
764 return m_ul_tbf->first_common_ts;
765
766 return -1;
767}
768
Jacob Erlbeck617c7122015-06-30 09:18:30 +0200769uint8_t GprsMs::dl_slots() const
770{
771 uint8_t slots = 0;
772
773 if (m_dl_tbf)
774 slots |= m_dl_tbf->dl_slots();
775
776 if (m_ul_tbf)
777 slots |= m_ul_tbf->dl_slots();
778
779 return slots;
780}
781
782uint8_t GprsMs::ul_slots() const
783{
784 uint8_t slots = 0;
785
786 if (m_dl_tbf)
787 slots |= m_dl_tbf->ul_slots();
788
789 if (m_ul_tbf)
790 slots |= m_ul_tbf->ul_slots();
791
792 return slots;
793}
794
Jacob Erlbeck7c72aca2016-01-22 17:06:14 +0100795uint8_t GprsMs::current_pacch_slots() const
796{
797 uint8_t slots = 0;
798
799 bool is_dl_active = m_dl_tbf && m_dl_tbf->is_tfi_assigned();
800 bool is_ul_active = m_ul_tbf && m_ul_tbf->is_tfi_assigned();
801
802 if (!is_dl_active && !is_ul_active)
803 return 0;
804
805 /* see TS 44.060, 8.1.1.2.2 */
806 if (is_dl_active && !is_ul_active)
807 slots = m_dl_tbf->dl_slots();
808 else if (!is_dl_active && is_ul_active)
809 slots = m_ul_tbf->ul_slots();
810 else
811 slots = m_ul_tbf->ul_slots() & m_dl_tbf->dl_slots();
812
813 /* Assume a multislot class 1 device */
814 /* TODO: For class 2 devices, this could be removed */
815 slots = pcu_lsb(slots);
816
817 return slots;
818}
819
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200820void GprsMs::set_reserved_slots(gprs_rlcmac_trx *trx,
821 uint8_t ul_slots, uint8_t dl_slots)
822{
823 if (m_current_trx) {
824 m_current_trx->unreserve_slots(GPRS_RLCMAC_DL_TBF,
825 m_reserved_dl_slots);
826 m_current_trx->unreserve_slots(GPRS_RLCMAC_UL_TBF,
827 m_reserved_ul_slots);
828 m_reserved_dl_slots = 0;
829 m_reserved_ul_slots = 0;
830 }
831 m_current_trx = trx;
832 if (trx) {
833 m_reserved_dl_slots = dl_slots;
834 m_reserved_ul_slots = ul_slots;
835 m_current_trx->reserve_slots(GPRS_RLCMAC_DL_TBF,
836 m_reserved_dl_slots);
837 m_current_trx->reserve_slots(GPRS_RLCMAC_UL_TBF,
838 m_reserved_ul_slots);
839 }
840}
841
Jacob Erlbeckac89a552015-06-29 14:18:46 +0200842gprs_rlcmac_tbf *GprsMs::tbf(enum gprs_rlcmac_tbf_direction dir) const
843{
844 switch (dir) {
845 case GPRS_RLCMAC_DL_TBF: return m_dl_tbf;
846 case GPRS_RLCMAC_UL_TBF: return m_ul_tbf;
847 }
848
849 return NULL;
850}