blob: 102f558f2245a506ec0e47f4cc3a070422a07379 [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>
Pau Espin Pedrol1de68732020-03-11 14:04:52 +010036 #include <osmocom/core/timer.h>
Max9bbe1602016-07-18 12:50:18 +020037 #include <osmocom/gsm/protocol/gsm_04_08.h>
Max1187a772018-01-26 13:31:42 +010038 #include <osmocom/core/logging.h>
Max136ebcc2019-03-05 14:59:03 +010039 #include "coding_scheme.h"
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020040}
41
Jacob Erlbeck1c3b8992015-08-14 16:01:36 +020042#define GPRS_CODEL_SLOW_INTERVAL_MS 4000
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +020043
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020044extern void *tall_pcu_ctx;
45
Jacob Erlbeck8158ea72015-06-04 17:46:33 +020046static int64_t now_msec()
47{
48 struct timespec ts;
Pau Espin Pedrol1de68732020-03-11 14:04:52 +010049 osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
Jacob Erlbeck8158ea72015-06-04 17:46:33 +020050
51 return int64_t(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
52}
53
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020054struct GprsMsDefaultCallback: public GprsMs::Callback {
55 virtual void ms_idle(class GprsMs *ms) {
56 delete ms;
57 }
58 virtual void ms_active(class GprsMs *) {}
59};
60
61static GprsMsDefaultCallback gprs_default_cb;
62
Jacob Erlbeckd9e10242015-05-28 15:43:53 +020063GprsMs::Guard::Guard(GprsMs *ms) :
64 m_ms(ms ? ms->ref() : NULL)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020065{
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020066}
67
68GprsMs::Guard::~Guard()
69{
70 if (m_ms)
71 m_ms->unref();
72}
73
Jacob Erlbeckb2439bb2015-07-13 14:23:32 +020074bool GprsMs::Guard::is_idle() const
75{
76 if (!m_ms)
77 return true;
78
79 return !m_ms->m_ul_tbf && !m_ms->m_dl_tbf && m_ms->m_ref == 1;
80}
81
Jacob Erlbeckd9e10242015-05-28 15:43:53 +020082void GprsMs::timeout(void *priv_)
83{
84 GprsMs *ms = static_cast<GprsMs *>(priv_);
85
86 LOGP(DRLCMAC, LOGL_INFO, "Timeout for MS object, TLLI = 0x%08x\n",
87 ms->tlli());
88
89 if (ms->m_timer.data) {
90 ms->m_timer.data = NULL;
91 ms->unref();
92 }
93}
94
Jacob Erlbeck17214bb2015-06-02 14:06:12 +020095GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
96 m_bts(bts),
Jacob Erlbecke04e0b02015-05-06 18:30:48 +020097 m_cb(&gprs_default_cb),
98 m_ul_tbf(NULL),
99 m_dl_tbf(NULL),
100 m_tlli(tlli),
Jacob Erlbeck93990462015-05-15 15:50:43 +0200101 m_new_ul_tlli(0),
102 m_new_dl_tlli(0),
Max9bbe1602016-07-18 12:50:18 +0200103 m_ta(GSM48_TA_INVALID),
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200104 m_ms_class(0),
Jacob Erlbeckc3c58042015-09-28 17:55:32 +0200105 m_egprs_ms_class(0),
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200106 m_is_idle(true),
Jacob Erlbeck53670862015-05-12 17:54:33 +0200107 m_ref(0),
Jacob Erlbeck25db7c62015-06-11 12:59:01 +0200108 m_list(this),
Jacob Erlbeck04a10862015-06-12 16:01:56 +0200109 m_delay(0),
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200110 m_nack_rate_dl(0),
111 m_reserved_dl_slots(0),
112 m_reserved_ul_slots(0),
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200113 m_current_trx(NULL),
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100114 m_codel_state(NULL),
Maxa4de02d2019-03-13 16:35:09 +0100115 m_mode(GPRS),
sivasankarida7250a2016-12-16 12:57:18 +0530116 m_dl_ctrl_msg(0)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200117{
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200118 int codel_interval = LLC_CODEL_USE_DEFAULT;
119
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200120 LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
Jacob Erlbeckb0e5eaf2015-05-21 11:07:16 +0200121
122 m_imsi[0] = 0;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200123 memset(&m_timer, 0, sizeof(m_timer));
124 m_timer.cb = GprsMs::timeout;
Jacob Erlbeck489a2b32015-05-28 19:07:01 +0200125 m_llc_queue.init();
Jacob Erlbecka700dd92015-06-02 16:00:41 +0200126
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100127 set_mode(m_mode);
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200128
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100129 if (m_bts)
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200130 codel_interval = m_bts->bts_data()->llc_codel_interval_msec;
Jacob Erlbeckd4ad7312015-07-17 16:39:09 +0200131
132 if (codel_interval) {
133 if (codel_interval == LLC_CODEL_USE_DEFAULT)
134 codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS;
135 m_codel_state = talloc(this, struct gprs_codel);
136 gprs_codel_init(m_codel_state);
137 gprs_codel_set_interval(m_codel_state, codel_interval);
Jacob Erlbecka700dd92015-06-02 16:00:41 +0200138 }
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200139 m_last_cs_not_low = now_msec();
Oliver Smithcfb63212019-09-05 17:13:33 +0200140 app_info_pending = false;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200141}
142
143GprsMs::~GprsMs()
144{
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200145 LListHead<gprs_rlcmac_tbf> *pos, *tmp;
146
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200147 LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", tlli());
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200148
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200149 set_reserved_slots(NULL, 0, 0);
150
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200151 if (osmo_timer_pending(&m_timer))
152 osmo_timer_del(&m_timer);
153
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200154 if (m_ul_tbf) {
155 m_ul_tbf->set_ms(NULL);
156 m_ul_tbf = NULL;
157 }
158
159 if (m_dl_tbf) {
160 m_dl_tbf->set_ms(NULL);
161 m_dl_tbf = NULL;
162 }
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200163
164 llist_for_each_safe(pos, tmp, &m_old_tbfs)
165 pos->entry()->set_ms(NULL);
166
Jacob Erlbeck17214bb2015-06-02 14:06:12 +0200167 m_llc_queue.clear(m_bts);
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200168}
169
170void* GprsMs::operator new(size_t size)
171{
172 static void *tall_ms_ctx = NULL;
173 if (!tall_ms_ctx)
174 tall_ms_ctx = talloc_named_const(tall_pcu_ctx, 0, __PRETTY_FUNCTION__);
175
176 return talloc_size(tall_ms_ctx, size);
177}
178
179void GprsMs::operator delete(void* p)
180{
181 talloc_free(p);
182}
183
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200184GprsMs *GprsMs::ref()
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200185{
186 m_ref += 1;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200187 return this;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200188}
189
190void GprsMs::unref()
191{
192 OSMO_ASSERT(m_ref >= 0);
193 m_ref -= 1;
194 if (m_ref == 0)
195 update_status();
196}
197
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200198void GprsMs::start_timer()
199{
200 if (m_delay == 0)
201 return;
202
203 if (!m_timer.data)
204 m_timer.data = ref();
205
206 osmo_timer_schedule(&m_timer, m_delay, 0);
207}
208
209void GprsMs::stop_timer()
210{
211 if (!m_timer.data)
212 return;
213
214 osmo_timer_del(&m_timer);
215 m_timer.data = NULL;
216 unref();
217}
218
Maxa4de02d2019-03-13 16:35:09 +0100219void GprsMs::set_mode(enum mcs_kind mode)
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100220{
221 m_mode = mode;
222
Jacob Erlbeck53bc1862016-01-18 17:23:09 +0100223 if (!m_bts)
224 return;
225
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100226 switch (m_mode) {
Maxa4de02d2019-03-13 16:35:09 +0100227 case GPRS:
Max8a8e0fb2019-03-25 16:32:50 +0100228 if (!mcs_is_gprs(m_current_cs_ul)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100229 m_current_cs_ul = GprsCodingScheme::getGprsByNum(
230 m_bts->bts_data()->initial_cs_ul);
231 if (!m_current_cs_ul.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100232 m_current_cs_ul = CS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100233 }
Max8a8e0fb2019-03-25 16:32:50 +0100234 if (!mcs_is_gprs(m_current_cs_dl)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100235 m_current_cs_dl = GprsCodingScheme::getGprsByNum(
236 m_bts->bts_data()->initial_cs_dl);
237 if (!m_current_cs_dl.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100238 m_current_cs_dl = CS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100239 }
240 break;
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100241
Maxa4de02d2019-03-13 16:35:09 +0100242 case EGPRS_GMSK:
243 case EGPRS:
Max8a8e0fb2019-03-25 16:32:50 +0100244 if (!mcs_is_edge(m_current_cs_ul)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100245 m_current_cs_ul = GprsCodingScheme::getEgprsByNum(
246 m_bts->bts_data()->initial_mcs_ul);
Holger Hans Peter Freytherfd263b02016-03-04 18:24:50 +0100247 if (!m_current_cs_ul.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100248 m_current_cs_ul = MCS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100249 }
Max8a8e0fb2019-03-25 16:32:50 +0100250 if (!mcs_is_edge(m_current_cs_dl)) {
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100251 m_current_cs_dl = GprsCodingScheme::getEgprsByNum(
252 m_bts->bts_data()->initial_mcs_dl);
253 if (!m_current_cs_dl.isValid())
Maxbea2edb2019-03-06 17:04:59 +0100254 m_current_cs_dl = MCS1;
Holger Hans Peter Freyther99db40a2016-03-04 18:19:02 +0100255 }
256 break;
257 }
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100258}
259
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200260void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf)
261{
262 if (tbf->direction == GPRS_RLCMAC_DL_TBF)
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100263 attach_dl_tbf(as_dl_tbf(tbf));
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200264 else
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100265 attach_ul_tbf(as_ul_tbf(tbf));
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200266}
267
268void GprsMs::attach_ul_tbf(struct gprs_rlcmac_ul_tbf *tbf)
269{
270 if (m_ul_tbf == tbf)
271 return;
272
273 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
274 tlli(), tbf->name());
275
276 Guard guard(this);
277
278 if (m_ul_tbf)
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200279 llist_add_tail(&m_ul_tbf->ms_list(), &m_old_tbfs);
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200280
281 m_ul_tbf = tbf;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200282
283 if (tbf)
284 stop_timer();
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200285}
286
287void GprsMs::attach_dl_tbf(struct gprs_rlcmac_dl_tbf *tbf)
288{
289 if (m_dl_tbf == tbf)
290 return;
291
292 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
293 tlli(), tbf->name());
294
295 Guard guard(this);
296
297 if (m_dl_tbf)
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200298 llist_add_tail(&m_dl_tbf->ms_list(), &m_old_tbfs);
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200299
300 m_dl_tbf = tbf;
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200301
302 if (tbf)
303 stop_timer();
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200304}
305
306void GprsMs::detach_tbf(gprs_rlcmac_tbf *tbf)
307{
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200308 if (tbf == static_cast<gprs_rlcmac_tbf *>(m_ul_tbf)) {
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200309 m_ul_tbf = NULL;
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200310 } else if (tbf == static_cast<gprs_rlcmac_tbf *>(m_dl_tbf)) {
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200311 m_dl_tbf = NULL;
Jacob Erlbeck6835cea2015-08-21 15:24:02 +0200312 } else {
313 bool found = false;
314
315 LListHead<gprs_rlcmac_tbf> *pos, *tmp;
316 llist_for_each_safe(pos, tmp, &m_old_tbfs) {
317 if (pos->entry() == tbf) {
318 llist_del(pos);
319 found = true;
320 break;
321 }
322 }
323
324 /* Protect against recursive calls via set_ms() */
325 if (!found)
326 return;
327 }
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200328
329 LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n",
330 tlli(), tbf->name());
331
Jacob Erlbeckfecece02015-05-08 12:13:08 +0200332 if (tbf->ms() == this)
333 tbf->set_ms(NULL);
334
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200335 if (!m_dl_tbf && !m_ul_tbf) {
336 set_reserved_slots(NULL, 0, 0);
337
338 if (tlli() != 0)
339 start_timer();
340 }
Jacob Erlbeckd9e10242015-05-28 15:43:53 +0200341
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200342 update_status();
343}
344
345void GprsMs::update_status()
346{
347 if (m_ref > 0)
348 return;
349
350 if (is_idle() && !m_is_idle) {
351 m_is_idle = true;
352 m_cb->ms_idle(this);
353 /* this can be deleted by now, do not access it */
354 return;
355 }
356
357 if (!is_idle() && m_is_idle) {
358 m_is_idle = false;
359 m_cb->ms_active(this);
360 }
361}
362
Jacob Erlbeckac289052015-08-14 12:50:54 +0200363void GprsMs::reset()
364{
365 LOGP(DRLCMAC, LOGL_INFO,
366 "Clearing MS object, TLLI: 0x%08x, IMSI: '%s'\n",
367 tlli(), imsi());
368
369 stop_timer();
370
371 m_tlli = 0;
372 m_new_dl_tlli = 0;
373 m_new_ul_tlli = 0;
374 m_imsi[0] = '\0';
375}
376
Jacob Erlbeck2b349b52015-08-18 11:55:03 +0200377void GprsMs::merge_old_ms(GprsMs *old_ms)
378{
379 if (old_ms == this)
380 return;
381
382 if (strlen(imsi()) == 0 && strlen(old_ms->imsi()) != 0)
383 set_imsi(old_ms->imsi());
384
385 if (!ms_class() && old_ms->ms_class())
386 set_ms_class(old_ms->ms_class());
387
Jacob Erlbecke0b21f42015-08-21 18:30:05 +0200388 m_llc_queue.move_and_merge(&old_ms->m_llc_queue);
389
Jacob Erlbeck2b349b52015-08-18 11:55:03 +0200390 old_ms->reset();
391}
392
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200393void GprsMs::set_tlli(uint32_t tlli)
394{
Jacob Erlbeck93990462015-05-15 15:50:43 +0200395 if (tlli == m_tlli || tlli == m_new_ul_tlli)
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200396 return;
397
Jacob Erlbeck93990462015-05-15 15:50:43 +0200398 if (tlli != m_new_dl_tlli) {
399 LOGP(DRLCMAC, LOGL_INFO,
400 "Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
401 "not yet confirmed\n",
402 this->tlli(), tlli);
403 m_new_ul_tlli = tlli;
404 return;
405 }
406
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200407 LOGP(DRLCMAC, LOGL_INFO,
Jacob Erlbeck93990462015-05-15 15:50:43 +0200408 "Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
409 "already confirmed partly\n",
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200410 m_tlli, tlli);
411
412 m_tlli = tlli;
Jacob Erlbeck93990462015-05-15 15:50:43 +0200413 m_new_dl_tlli = 0;
414 m_new_ul_tlli = 0;
415}
416
417bool GprsMs::confirm_tlli(uint32_t tlli)
418{
419 if (tlli == m_tlli || tlli == m_new_dl_tlli)
420 return false;
421
422 if (tlli != m_new_ul_tlli) {
423 /* The MS has not sent a message with the new TLLI, which may
424 * happen according to the spec [TODO: add reference]. */
425
426 LOGP(DRLCMAC, LOGL_INFO,
427 "The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
428 "partly confirmed\n", tlli);
429 /* Use the network's idea of TLLI as candidate, this does not
430 * change the result value of tlli() */
431 m_new_dl_tlli = tlli;
432 return false;
433 }
434
435 LOGP(DRLCMAC, LOGL_INFO,
436 "Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
437
438 m_tlli = tlli;
439 m_new_dl_tlli = 0;
440 m_new_ul_tlli = 0;
441
442 return true;
Jacob Erlbecke04e0b02015-05-06 18:30:48 +0200443}
Jacob Erlbeckb0e5eaf2015-05-21 11:07:16 +0200444
445void GprsMs::set_imsi(const char *imsi)
446{
447 if (!imsi) {
448 LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");
449 return;
450 }
451
452 if (imsi[0] && strlen(imsi) < 3) {
453 LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",
454 imsi);
455 return;
456 }
457
458 if (strcmp(imsi, m_imsi) == 0)
459 return;
460
461 LOGP(DRLCMAC, LOGL_INFO,
462 "Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",
463 tlli(), m_imsi, imsi);
464
465 strncpy(m_imsi, imsi, sizeof(m_imsi));
466 m_imsi[sizeof(m_imsi) - 1] = '\0';
467}
468
Jacob Erlbeck9200ce62015-05-22 17:48:04 +0200469void GprsMs::set_ta(uint8_t ta_)
470{
471 if (ta_ == m_ta)
472 return;
473
Max9bbe1602016-07-18 12:50:18 +0200474 if (gsm48_ta_is_valid(ta_)) {
475 LOGP(DRLCMAC, LOGL_INFO,
476 "Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
477 tlli(), m_ta, ta_);
478 m_ta = ta_;
479 } else
480 LOGP(DRLCMAC, LOGL_NOTICE,
481 "MS object, TLLI = 0x%08x, invalid TA %d rejected (old "
482 "value %d kept)\n", tlli(), ta_, m_ta);
Jacob Erlbeck9200ce62015-05-22 17:48:04 +0200483}
484
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200485void GprsMs::set_ms_class(uint8_t ms_class_)
486{
487 if (ms_class_ == m_ms_class)
488 return;
489
490 LOGP(DRLCMAC, LOGL_INFO,
491 "Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",
492 tlli(), m_ms_class, ms_class_);
493
494 m_ms_class = ms_class_;
495}
496
Jacob Erlbeckc3c58042015-09-28 17:55:32 +0200497void GprsMs::set_egprs_ms_class(uint8_t ms_class_)
498{
499 if (ms_class_ == m_egprs_ms_class)
500 return;
501
502 LOGP(DRLCMAC, LOGL_INFO,
503 "Modifying MS object, TLLI = 0x%08x, EGPRS MS class %d -> %d\n",
504 tlli(), m_egprs_ms_class, ms_class_);
505
506 m_egprs_ms_class = ms_class_;
507}
508
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200509void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
510{
511 struct gprs_rlcmac_bts *bts_data;
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200512 int64_t now;
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100513 GprsCodingScheme max_cs_dl = this->max_cs_dl();
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200514
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100515 OSMO_ASSERT(max_cs_dl);
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200516 bts_data = m_bts->bts_data();
517
518 if (error_rate < 0)
519 return;
520
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200521 now = now_msec();
522
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200523 /* TODO: Check for TBF direction */
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200524 /* TODO: Support different CS values for UL and DL */
525
Jacob Erlbeck04a10862015-06-12 16:01:56 +0200526 m_nack_rate_dl = error_rate;
527
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200528 if (error_rate > bts_data->cs_adj_upper_limit) {
Max898dddb2019-03-12 15:50:57 +0100529 if (mcs_chan_code(m_current_cs_dl) > 0) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100530 m_current_cs_dl.dec(mode());
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200531 LOGP(DRLCMACDL, LOGL_INFO,
532 "MS (IMSI %s): High error rate %d%%, "
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100533 "reducing CS level to %s\n",
Max136ebcc2019-03-05 14:59:03 +0100534 imsi(), error_rate, mcs_name(m_current_cs_dl));
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200535 m_last_cs_not_low = now;
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200536 }
537 } else if (error_rate < bts_data->cs_adj_lower_limit) {
Jacob Erlbeckb33e6752015-06-04 19:04:30 +0200538 if (m_current_cs_dl < max_cs_dl) {
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200539 if (now - m_last_cs_not_low > 1000) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100540 m_current_cs_dl.inc(mode());
Jacob Erlbeckb33e6752015-06-04 19:04:30 +0200541
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200542 LOGP(DRLCMACDL, LOGL_INFO,
543 "MS (IMSI %s): Low error rate %d%%, "
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100544 "increasing DL CS level to %s\n",
545 imsi(), error_rate,
Max136ebcc2019-03-05 14:59:03 +0100546 mcs_name(m_current_cs_dl));
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200547 m_last_cs_not_low = now;
548 } else {
549 LOGP(DRLCMACDL, LOGL_DEBUG,
550 "MS (IMSI %s): Low error rate %d%%, "
551 "ignored (within blocking period)\n",
552 imsi(), error_rate);
553 }
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200554 }
555 } else {
556 LOGP(DRLCMACDL, LOGL_DEBUG,
557 "MS (IMSI %s): Medium error rate %d%%, ignored\n",
558 imsi(), error_rate);
Jacob Erlbeck8158ea72015-06-04 17:46:33 +0200559 m_last_cs_not_low = now;
Jacob Erlbeck1751c622015-06-04 12:12:32 +0200560 }
561}
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200562
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100563GprsCodingScheme GprsMs::max_cs_ul() const
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200564{
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200565 struct gprs_rlcmac_bts *bts_data;
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200566
567 OSMO_ASSERT(m_bts != NULL);
568 bts_data = m_bts->bts_data();
569
Max8a8e0fb2019-03-25 16:32:50 +0100570 if (mcs_is_gprs(m_current_cs_ul)) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100571 if (!bts_data->max_cs_ul)
Maxbea2edb2019-03-06 17:04:59 +0100572 return GprsCodingScheme(CS4);
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200573
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100574 return GprsCodingScheme::getGprsByNum(bts_data->max_cs_ul);
Jacob Erlbeck94cde132015-06-09 09:44:36 +0200575 }
576
Max8a8e0fb2019-03-25 16:32:50 +0100577 if (!mcs_is_edge(m_current_cs_ul))
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100578 return GprsCodingScheme(); /* UNKNOWN */
579
580 if (bts_data->max_mcs_ul)
581 return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_ul);
582 else if (bts_data->max_cs_ul)
583 return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_ul);
584
Maxbea2edb2019-03-06 17:04:59 +0100585 return GprsCodingScheme(MCS4);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100586}
587
Maxbea2edb2019-03-06 17:04:59 +0100588void GprsMs::set_current_cs_dl(CodingScheme scheme)
Aravind Sirsikare8ccafc2016-07-13 11:37:47 +0530589{
590 m_current_cs_dl = scheme;
591}
592
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100593GprsCodingScheme GprsMs::max_cs_dl() const
594{
595 struct gprs_rlcmac_bts *bts_data;
596
597 OSMO_ASSERT(m_bts != NULL);
598 bts_data = m_bts->bts_data();
599
Max8a8e0fb2019-03-25 16:32:50 +0100600 if (mcs_is_gprs(m_current_cs_dl)) {
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100601 if (!bts_data->max_cs_dl)
Maxbea2edb2019-03-06 17:04:59 +0100602 return GprsCodingScheme(CS4);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100603
604 return GprsCodingScheme::getGprsByNum(bts_data->max_cs_dl);
605 }
606
Max8a8e0fb2019-03-25 16:32:50 +0100607 if (!mcs_is_edge(m_current_cs_dl))
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100608 return GprsCodingScheme(); /* UNKNOWN */
609
610 if (bts_data->max_mcs_dl)
611 return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_dl);
612 else if (bts_data->max_cs_dl)
613 return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_dl);
614
Maxbea2edb2019-03-06 17:04:59 +0100615 return GprsCodingScheme(MCS4);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100616}
617
618void GprsMs::update_cs_ul(const pcu_l1_meas *meas)
619{
620 struct gprs_rlcmac_bts *bts_data;
621 GprsCodingScheme max_cs_ul = this->max_cs_ul();
622
623 int old_link_qual;
624 int low;
625 int high;
626 GprsCodingScheme new_cs_ul = m_current_cs_ul;
Max898dddb2019-03-12 15:50:57 +0100627 uint8_t current_cs = mcs_chan_code(m_current_cs_ul);
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100628
629 bts_data = m_bts->bts_data();
630
631 if (!max_cs_ul) {
Minh-Quang Nguyen1f189092017-08-16 09:50:06 -0400632 LOGP(DRLCMACMEAS, LOGL_ERROR,
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100633 "max_cs_ul cannot be derived (current UL CS: %s)\n",
Max136ebcc2019-03-05 14:59:03 +0100634 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100635 return;
636 }
637
Maxfa3085b2019-03-07 11:46:43 +0100638 if (!m_current_cs_ul) {
639 LOGP(DRLCMACMEAS, LOGL_ERROR,
640 "Unable to update UL (M)CS because it's not set: %s\n",
Max136ebcc2019-03-05 14:59:03 +0100641 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100642 return;
Maxfa3085b2019-03-07 11:46:43 +0100643 }
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100644
Maxfa3085b2019-03-07 11:46:43 +0100645 if (!meas->have_link_qual) {
646 LOGP(DRLCMACMEAS, LOGL_ERROR,
647 "Unable to update UL (M)CS %s because we don't have link quality measurements.\n",
Max136ebcc2019-03-05 14:59:03 +0100648 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100649 return;
Maxfa3085b2019-03-07 11:46:43 +0100650 }
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100651
Max8a8e0fb2019-03-25 16:32:50 +0100652 if (mcs_is_gprs(m_current_cs_ul)) {
Max898dddb2019-03-12 15:50:57 +0100653 if (current_cs >= MAX_GPRS_CS)
654 current_cs = MAX_GPRS_CS - 1;
655 low = bts_data->cs_lqual_ranges[current_cs].low;
656 high = bts_data->cs_lqual_ranges[current_cs].high;
Max8a8e0fb2019-03-25 16:32:50 +0100657 } else if (mcs_is_edge(m_current_cs_ul)) {
Max898dddb2019-03-12 15:50:57 +0100658 if (current_cs >= MAX_EDGE_MCS)
659 current_cs = MAX_EDGE_MCS - 1;
660 low = bts_data->mcs_lqual_ranges[current_cs].low;
661 high = bts_data->mcs_lqual_ranges[current_cs].high;
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100662 } else {
Maxfa3085b2019-03-07 11:46:43 +0100663 LOGP(DRLCMACMEAS, LOGL_ERROR,
664 "Unable to update UL (M)CS because it's neither GPRS nor EDGE: %s\n",
Max136ebcc2019-03-05 14:59:03 +0100665 mcs_name(m_current_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100666 return;
667 }
668
Vadim Yanitskiyfd734de2019-11-08 05:37:18 +0700669 /* To avoid rapid changes of the coding scheme, we also take
670 * the old link quality value into account (if present). */
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100671 if (m_l1_meas.have_link_qual)
672 old_link_qual = m_l1_meas.link_qual;
Vadim Yanitskiyfd734de2019-11-08 05:37:18 +0700673 else
674 old_link_qual = meas->link_qual;
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100675
676 if (meas->link_qual < low && old_link_qual < low)
677 new_cs_ul.dec(mode());
678 else if (meas->link_qual > high && old_link_qual > high &&
679 m_current_cs_ul < max_cs_ul)
680 new_cs_ul.inc(mode());
681
682 if (m_current_cs_ul != new_cs_ul) {
Minh-Quang Nguyen1f189092017-08-16 09:50:06 -0400683 LOGP(DRLCMACMEAS, LOGL_INFO,
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100684 "MS (IMSI %s): "
Vadim Yanitskiyfd734de2019-11-08 05:37:18 +0700685 "Link quality %ddB (old %ddB) left window [%d, %d], "
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100686 "modifying uplink CS level: %s -> %s\n",
687 imsi(), meas->link_qual, old_link_qual,
688 low, high,
Max136ebcc2019-03-05 14:59:03 +0100689 mcs_name(m_current_cs_ul), mcs_name(new_cs_ul));
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100690
691 m_current_cs_ul = new_cs_ul;
692 }
693}
694
695void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
696{
697 unsigned i;
698
699 update_cs_ul(meas);
700
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200701 if (meas->have_rssi)
702 m_l1_meas.set_rssi(meas->rssi);
703 if (meas->have_bto)
704 m_l1_meas.set_bto(meas->bto);
705 if (meas->have_ber)
706 m_l1_meas.set_ber(meas->ber);
707 if (meas->have_link_qual)
708 m_l1_meas.set_link_qual(meas->link_qual);
Jacob Erlbeck51b11512015-06-11 16:54:50 +0200709
710 if (meas->have_ms_rx_qual)
711 m_l1_meas.set_ms_rx_qual(meas->ms_rx_qual);
712 if (meas->have_ms_c_value)
713 m_l1_meas.set_ms_c_value(meas->ms_c_value);
714 if (meas->have_ms_sign_var)
715 m_l1_meas.set_ms_sign_var(meas->ms_sign_var);
716
717 if (meas->have_ms_i_level) {
718 for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
719 if (meas->ts[i].have_ms_i_level)
720 m_l1_meas.set_ms_i_level(i, meas->ts[i].ms_i_level);
721 else
722 m_l1_meas.ts[i].have_ms_i_level = 0;
723 }
724 }
Jacob Erlbecke4bcb622015-06-08 11:26:38 +0200725}
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200726
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100727GprsCodingScheme GprsMs::current_cs_dl() const
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200728{
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100729 GprsCodingScheme cs = m_current_cs_dl;
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200730 size_t unencoded_octets;
731
732 if (!m_bts)
733 return cs;
734
735 unencoded_octets = m_llc_queue.octets();
736
737 /* If the DL TBF is active, add number of unencoded chunk octets */
738 if (m_dl_tbf)
Jacob Erlbeck14e26cb2016-02-03 15:26:29 +0100739 unencoded_octets += m_dl_tbf->m_llc.chunk_size();
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200740
741 /* There are many unencoded octets, don't reduce */
742 if (unencoded_octets >= m_bts->bts_data()->cs_downgrade_threshold)
743 return cs;
744
745 /* RF conditions are good, don't reduce */
746 if (m_nack_rate_dl < m_bts->bts_data()->cs_adj_lower_limit)
747 return cs;
748
749 /* The throughput would probably be better if the CS level was reduced */
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100750 cs.dec(mode());
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200751
752 /* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
Maxbea2edb2019-03-06 17:04:59 +0100753 if (cs == GprsCodingScheme(CS2))
Jacob Erlbeckcb728902016-01-05 15:33:03 +0100754 cs.dec(mode());
Jacob Erlbeck70b96aa2015-06-12 10:52:34 +0200755
756 return cs;
757}
758
Jacob Erlbeck699b8dc2015-06-29 14:05:55 +0200759int GprsMs::first_common_ts() const
760{
761 if (m_dl_tbf)
762 return m_dl_tbf->first_common_ts;
763
764 if (m_ul_tbf)
765 return m_ul_tbf->first_common_ts;
766
767 return -1;
768}
769
Jacob Erlbeck617c7122015-06-30 09:18:30 +0200770uint8_t GprsMs::dl_slots() const
771{
772 uint8_t slots = 0;
773
774 if (m_dl_tbf)
775 slots |= m_dl_tbf->dl_slots();
776
777 if (m_ul_tbf)
778 slots |= m_ul_tbf->dl_slots();
779
780 return slots;
781}
782
783uint8_t GprsMs::ul_slots() const
784{
785 uint8_t slots = 0;
786
787 if (m_dl_tbf)
788 slots |= m_dl_tbf->ul_slots();
789
790 if (m_ul_tbf)
791 slots |= m_ul_tbf->ul_slots();
792
793 return slots;
794}
795
Jacob Erlbeck7c72aca2016-01-22 17:06:14 +0100796uint8_t GprsMs::current_pacch_slots() const
797{
798 uint8_t slots = 0;
799
800 bool is_dl_active = m_dl_tbf && m_dl_tbf->is_tfi_assigned();
801 bool is_ul_active = m_ul_tbf && m_ul_tbf->is_tfi_assigned();
802
803 if (!is_dl_active && !is_ul_active)
804 return 0;
805
806 /* see TS 44.060, 8.1.1.2.2 */
807 if (is_dl_active && !is_ul_active)
808 slots = m_dl_tbf->dl_slots();
809 else if (!is_dl_active && is_ul_active)
810 slots = m_ul_tbf->ul_slots();
811 else
812 slots = m_ul_tbf->ul_slots() & m_dl_tbf->dl_slots();
813
814 /* Assume a multislot class 1 device */
815 /* TODO: For class 2 devices, this could be removed */
816 slots = pcu_lsb(slots);
817
818 return slots;
819}
820
Jacob Erlbeck23f93a12015-06-30 08:52:54 +0200821void GprsMs::set_reserved_slots(gprs_rlcmac_trx *trx,
822 uint8_t ul_slots, uint8_t dl_slots)
823{
824 if (m_current_trx) {
825 m_current_trx->unreserve_slots(GPRS_RLCMAC_DL_TBF,
826 m_reserved_dl_slots);
827 m_current_trx->unreserve_slots(GPRS_RLCMAC_UL_TBF,
828 m_reserved_ul_slots);
829 m_reserved_dl_slots = 0;
830 m_reserved_ul_slots = 0;
831 }
832 m_current_trx = trx;
833 if (trx) {
834 m_reserved_dl_slots = dl_slots;
835 m_reserved_ul_slots = ul_slots;
836 m_current_trx->reserve_slots(GPRS_RLCMAC_DL_TBF,
837 m_reserved_dl_slots);
838 m_current_trx->reserve_slots(GPRS_RLCMAC_UL_TBF,
839 m_reserved_ul_slots);
840 }
841}
842
Jacob Erlbeckac89a552015-06-29 14:18:46 +0200843gprs_rlcmac_tbf *GprsMs::tbf(enum gprs_rlcmac_tbf_direction dir) const
844{
845 switch (dir) {
846 case GPRS_RLCMAC_DL_TBF: return m_dl_tbf;
847 case GPRS_RLCMAC_UL_TBF: return m_ul_tbf;
848 }
849
850 return NULL;
851}