blob: 6fbb06a82a35b7389d8067c3669484e4cd892946 [file] [log] [blame]
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +01001/* gprs_ms.c
2 *
3 * Copyright (C) 2015-2020 by Sysmocom s.f.m.c. GmbH
4 * Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21
22#include "gprs_ms.h"
23#include "bts.h"
24#include "tbf.h"
25#include "tbf_ul.h"
26#include "gprs_debug.h"
27#include "gprs_codel.h"
28#include "pcu_utils.h"
29
30#include <time.h>
31
32#include <osmocom/core/talloc.h>
33#include <osmocom/core/utils.h>
34#include <osmocom/core/timer.h>
35#include <osmocom/gsm/protocol/gsm_04_08.h>
36#include <osmocom/gsm/gsm48.h>
37#include <osmocom/core/logging.h>
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +010038#include <osmocom/core/stats.h>
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010039#include "coding_scheme.h"
40
41#define GPRS_CODEL_SLOW_INTERVAL_MS 4000
42
43extern void *tall_pcu_ctx;
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +010044static unsigned int next_ms_ctr_group_id;
45
46static const struct rate_ctr_desc ms_ctr_description[] = {
47 [MS_CTR_DL_CTRL_MSG_SCHED] = { "ms:dl_ctrl_msg_sched", "Amount of DL CTRL messages scheduled" },
48};
49
Pau Espin Pedrolf5a251b2021-01-12 20:57:56 +010050static const struct rate_ctr_group_desc ms_ctrg_desc = {
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +010051 .group_name_prefix = "pcu:ms",
52 .group_description = "MS Statistics",
53 .class_id = OSMO_STATS_CLASS_SUBSCRIBER,
54 .num_ctr = ARRAY_SIZE(ms_ctr_description),
55 .ctr_desc = ms_ctr_description,
56};
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010057
58static int64_t now_msec()
59{
60 struct timespec ts;
61 osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
62
63 return (int64_t)(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
64}
65
66void gprs_default_cb_ms_idle(struct GprsMs *ms)
67{
68 talloc_free(ms);
69}
70
71void gprs_default_cb_ms_active(struct GprsMs *ms)
72{
73 /* do nothing */
74}
75
76static struct gpr_ms_callback gprs_default_cb = {
77 .ms_idle = gprs_default_cb_ms_idle,
78 .ms_active = gprs_default_cb_ms_active,
79};
80
81void ms_timeout(void *data)
82{
83 struct GprsMs *ms = (struct GprsMs *) data;
84 LOGP(DRLCMAC, LOGL_INFO, "Timeout for MS object, TLLI = 0x%08x\n",
85 ms_tlli(ms));
86
87 if (ms->timer.data) {
88 ms->timer.data = NULL;
89 ms_unref(ms);
90 }
91}
92
93static int ms_talloc_destructor(struct GprsMs *ms);
94struct GprsMs *ms_alloc(struct BTS *bts, uint32_t tlli)
95{
96 struct GprsMs *ms = talloc_zero(tall_pcu_ctx, struct GprsMs);
97
98 talloc_set_destructor(ms, ms_talloc_destructor);
99
100 ms->bts = bts;
101 ms->cb = gprs_default_cb;
102 ms->tlli = tlli;
103 ms->new_ul_tlli = GSM_RESERVED_TMSI;
104 ms->new_dl_tlli = GSM_RESERVED_TMSI;
105 ms->ta = GSM48_TA_INVALID;
106 ms->current_cs_ul = UNKNOWN;
107 ms->current_cs_dl = UNKNOWN;
108 ms->is_idle = true;
109 INIT_LLIST_HEAD(&ms->list);
110 INIT_LLIST_HEAD(&ms->old_tbfs);
111
112 int codel_interval = LLC_CODEL_USE_DEFAULT;
113
114 LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
115
116 ms->imsi[0] = '\0';
117 memset(&ms->timer, 0, sizeof(ms->timer));
118 ms->timer.cb = ms_timeout;
119 llc_queue_init(&ms->llc_queue);
120
121 ms_set_mode(ms, GPRS);
122
123 if (ms->bts)
124 codel_interval = bts_data(ms->bts)->llc_codel_interval_msec;
125
126 if (codel_interval) {
127 if (codel_interval == LLC_CODEL_USE_DEFAULT)
128 codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS;
129 ms->codel_state = talloc(ms, struct gprs_codel);
130 gprs_codel_init(ms->codel_state);
131 gprs_codel_set_interval(ms->codel_state, codel_interval);
132 }
133 ms->last_cs_not_low = now_msec();
134 ms->app_info_pending = false;
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +0100135
136 ms->ctrs = rate_ctr_group_alloc(ms, &ms_ctrg_desc, next_ms_ctr_group_id++);
137 if (!ms->ctrs)
138 goto free_ret;
139
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100140 return ms;
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +0100141free_ret:
142 talloc_free(ms);
143 return NULL;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100144}
145
146static int ms_talloc_destructor(struct GprsMs *ms)
147{
148 struct llist_item *pos, *tmp;
149
150 LOGP(DRLCMAC, LOGL_INFO, "Destroying MS object, TLLI = 0x%08x\n", ms_tlli(ms));
151
152 ms_set_reserved_slots(ms, NULL, 0, 0);
153
154 if (osmo_timer_pending(&ms->timer))
155 osmo_timer_del(&ms->timer);
156
157 if (ms->ul_tbf) {
158 tbf_set_ms((struct gprs_rlcmac_tbf *)ms->ul_tbf, NULL);
159 ms->ul_tbf = NULL;
160 }
161
162 if (ms->dl_tbf) {
163 tbf_set_ms((struct gprs_rlcmac_tbf *)ms->dl_tbf, NULL);
164 ms->dl_tbf = NULL;
165 }
166
167 llist_for_each_entry_safe(pos, tmp, &ms->old_tbfs, list) {
168 struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)pos->entry;
169 tbf_set_ms(tbf, NULL);
170 }
171
172 llc_queue_clear(&ms->llc_queue, ms->bts);
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +0100173
174 if (ms->ctrs)
175 rate_ctr_group_free(ms->ctrs);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100176 return 0;
177}
178
179
180void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb)
181{
182 if (cb)
183 ms->cb = *cb;
184 else
185 ms->cb = gprs_default_cb;
186}
187
188static void ms_update_status(struct GprsMs *ms)
189{
190 if (ms->ref > 0)
191 return;
192
193 if (ms_is_idle(ms) && !ms->is_idle) {
194 ms->is_idle = true;
195 ms->cb.ms_idle(ms);
196 /* this can be deleted by now, do not access it */
197 return;
198 }
199
200 if (!ms_is_idle(ms) && ms->is_idle) {
201 ms->is_idle = false;
202 ms->cb.ms_active(ms);
203 }
204}
205
206struct GprsMs *ms_ref(struct GprsMs *ms)
207{
208 ms->ref += 1;
209 return ms;
210}
211
212void ms_unref(struct GprsMs *ms)
213{
214 OSMO_ASSERT(ms->ref >= 0);
215 ms->ref -= 1;
216 if (ms->ref == 0)
217 ms_update_status(ms);
218}
219
220void ms_start_timer(struct GprsMs *ms)
221{
222 if (ms->delay == 0)
223 return;
224
225 if (!ms->timer.data)
226 ms->timer.data = ms_ref(ms);
227
228 osmo_timer_schedule(&ms->timer, ms->delay, 0);
229}
230
231void ms_stop_timer(struct GprsMs *ms)
232{
233 if (!ms->timer.data)
234 return;
235
236 osmo_timer_del(&ms->timer);
237 ms->timer.data = NULL;
238 ms_unref(ms);
239}
240
241void ms_set_mode(struct GprsMs *ms, enum mcs_kind mode)
242{
243 ms->mode = mode;
244
245 if (!ms->bts)
246 return;
247
248 switch (ms->mode) {
249 case GPRS:
250 if (!mcs_is_gprs(ms->current_cs_ul)) {
251 ms->current_cs_ul = mcs_get_gprs_by_num(
252 bts_data(ms->bts)->initial_cs_ul);
253 if (!mcs_is_valid(ms->current_cs_ul))
254 ms->current_cs_ul = CS1;
255 }
256 if (!mcs_is_gprs(ms->current_cs_dl)) {
257 ms->current_cs_dl = mcs_get_gprs_by_num(
258 bts_data(ms->bts)->initial_cs_dl);
259 if (!mcs_is_valid(ms->current_cs_dl))
260 ms->current_cs_dl = CS1;
261 }
262 break;
263
264 case EGPRS_GMSK:
265 case EGPRS:
266 if (!mcs_is_edge(ms->current_cs_ul)) {
267 ms->current_cs_ul = mcs_get_egprs_by_num(
268 bts_data(ms->bts)->initial_mcs_ul);
269 if (!mcs_is_valid(ms->current_cs_ul))
270 ms->current_cs_ul = MCS1;
271 }
272 if (!mcs_is_edge(ms->current_cs_dl)) {
273 ms->current_cs_dl = mcs_get_egprs_by_num(
274 bts_data(ms->bts)->initial_mcs_dl);
275 if (!mcs_is_valid(ms->current_cs_dl))
276 ms->current_cs_dl = MCS1;
277 }
278 break;
279 }
280}
281
282static void ms_attach_ul_tbf(struct GprsMs *ms, struct gprs_rlcmac_ul_tbf *tbf)
283{
284 if (ms->ul_tbf == tbf)
285 return;
286
287 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
288 ms_tlli(ms), tbf_name((struct gprs_rlcmac_tbf *)tbf));
289
290 ms_ref(ms);
291
292 if (ms->ul_tbf)
293 llist_add_tail(tbf_ms_list((struct gprs_rlcmac_tbf *)ms->ul_tbf), &ms->old_tbfs);
294
295 ms->ul_tbf = tbf;
296
297 if (tbf)
298 ms_stop_timer(ms);
299
300 ms_unref(ms);
301}
302
303static void ms_attach_dl_tbf(struct GprsMs *ms, struct gprs_rlcmac_dl_tbf *tbf)
304{
305 if (ms->dl_tbf == tbf)
306 return;
307
308 LOGP(DRLCMAC, LOGL_INFO, "Attaching TBF to MS object, TLLI = 0x%08x, TBF = %s\n",
309 ms_tlli(ms), tbf_name((struct gprs_rlcmac_tbf *)tbf));
310
311 ms_ref(ms);
312
313 if (ms->dl_tbf)
314 llist_add_tail(tbf_ms_list((struct gprs_rlcmac_tbf *)ms->dl_tbf), &ms->old_tbfs);
315
316 ms->dl_tbf = tbf;
317
318 if (tbf)
319 ms_stop_timer(ms);
320
321 ms_unref(ms);
322}
323
324void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)
325{
326 if (tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF)
327 ms_attach_dl_tbf(ms, as_dl_tbf(tbf));
328 else
329 ms_attach_ul_tbf(ms, as_ul_tbf(tbf));
330}
331
332void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)
333{
334 if (tbf == (struct gprs_rlcmac_tbf *)(ms->ul_tbf)) {
335 ms->ul_tbf = NULL;
336 } else if (tbf == (struct gprs_rlcmac_tbf *)(ms->dl_tbf)) {
337 ms->dl_tbf = NULL;
338 } else {
339 bool found = false;
340
341 struct llist_item *pos, *tmp;
342 llist_for_each_entry_safe(pos, tmp, &ms->old_tbfs, list) {
343 struct gprs_rlcmac_tbf *tmp_tbf = (struct gprs_rlcmac_tbf *)pos->entry;
344 if (tmp_tbf == tbf) {
345 llist_del(&pos->list);
346 found = true;
347 break;
348 }
349 }
350
351 /* Protect against recursive calls via set_ms() */
352 if (!found)
353 return;
354 }
355
356 LOGP(DRLCMAC, LOGL_INFO, "Detaching TBF from MS object, TLLI = 0x%08x, TBF = %s\n",
357 ms_tlli(ms), tbf_name(tbf));
358
359 if (tbf_ms(tbf) == ms)
360 tbf_set_ms(tbf, NULL);
361
362 if (!ms->dl_tbf && !ms->ul_tbf) {
363 ms_set_reserved_slots(ms, NULL, 0, 0);
364
365 if (ms_tlli(ms) != 0)
366 ms_start_timer(ms);
367 }
368
369 ms_update_status(ms);
370}
371
372void ms_reset(struct GprsMs *ms)
373{
374 LOGP(DRLCMAC, LOGL_INFO,
375 "Clearing MS object, TLLI: 0x%08x, IMSI: '%s'\n",
376 ms_tlli(ms), ms_imsi(ms));
377
378 ms_stop_timer(ms);
379
380 ms->tlli = GSM_RESERVED_TMSI;
381 ms->new_dl_tlli = ms->tlli;
382 ms->new_ul_tlli = ms->tlli;
383 ms->imsi[0] = '\0';
384}
385
386static void ms_merge_old_ms(struct GprsMs *ms, struct GprsMs *old_ms)
387{
388 OSMO_ASSERT(old_ms != ms);
389
390 if (strlen(ms_imsi(ms)) == 0 && strlen(ms_imsi(old_ms)) != 0)
391 osmo_strlcpy(ms->imsi, ms_imsi(old_ms), sizeof(ms->imsi));
392
393 if (!ms_ms_class(ms) && ms_ms_class(old_ms))
394 ms_set_ms_class(ms, ms_ms_class(old_ms));
395
396 if (!ms_egprs_ms_class(ms) && ms_egprs_ms_class(old_ms))
397 ms_set_egprs_ms_class(ms, ms_egprs_ms_class(old_ms));
398
399 llc_queue_move_and_merge(&ms->llc_queue, &old_ms->llc_queue);
400
401 ms_reset(old_ms);
402}
403
404void ms_merge_and_clear_ms(struct GprsMs *ms, struct GprsMs *old_ms)
405{
406 OSMO_ASSERT(old_ms != ms);
407
408 ms_ref(old_ms);
409
410 /* Clean up the old MS object */
411 /* TODO: Use timer? */
412 if (ms_ul_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms), T_MAX))
413 tbf_free((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms));
414 if (ms_dl_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms), T_MAX))
415 tbf_free((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms));
416
417 ms_merge_old_ms(ms, old_ms);
418
419 ms_unref(old_ms);
420}
421
422void ms_set_tlli(struct GprsMs *ms, uint32_t tlli)
423{
424 if (tlli == ms->tlli || tlli == ms->new_ul_tlli)
425 return;
426
427 if (tlli != ms->new_dl_tlli) {
428 LOGP(DRLCMAC, LOGL_INFO,
429 "Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
430 "not yet confirmed\n",
431 ms_tlli(ms), tlli);
432 ms->new_ul_tlli = tlli;
433 return;
434 }
435
436 LOGP(DRLCMAC, LOGL_INFO,
437 "Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
438 "already confirmed partly\n",
439 ms->tlli, tlli);
440
441 ms->tlli = tlli;
442 ms->new_dl_tlli = GSM_RESERVED_TMSI;
443 ms->new_ul_tlli = GSM_RESERVED_TMSI;
444}
445
446bool ms_confirm_tlli(struct GprsMs *ms, uint32_t tlli)
447{
448 if (tlli == ms->tlli || tlli == ms->new_dl_tlli)
449 return false;
450
451 if (tlli != ms->new_ul_tlli) {
452 /* The MS has not sent a message with the new TLLI, which may
453 * happen according to the spec [TODO: add reference]. */
454
455 LOGP(DRLCMAC, LOGL_INFO,
456 "The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
457 "partly confirmed\n", tlli);
458 /* Use the network's idea of TLLI as candidate, this does not
459 * change the result value of tlli() */
460 ms->new_dl_tlli = tlli;
461 return false;
462 }
463
464 LOGP(DRLCMAC, LOGL_INFO,
465 "Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
466
467 ms->tlli = tlli;
468 ms->new_dl_tlli = GSM_RESERVED_TMSI;
469 ms->new_ul_tlli = GSM_RESERVED_TMSI;
470
471 return true;
472}
473
474void ms_set_imsi(struct GprsMs *ms, const char *imsi)
475{
476 if (!imsi) {
477 LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");
478 return;
479 }
480
481 if (imsi[0] && strlen(imsi) < 3) {
482 LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",
483 imsi);
484 return;
485 }
486
487 if (strcmp(imsi, ms->imsi) == 0)
488 return;
489
490 LOGP(DRLCMAC, LOGL_INFO,
491 "Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",
492 ms_tlli(ms), ms->imsi, imsi);
493
494 struct GprsMs *old_ms = bts_ms_by_imsi(ms->bts, imsi);
495 /* Check if we are going to store a different MS object with already
496 existing IMSI. This is probably a bug in code calling this function,
497 since it should take care of this explicitly */
498 if (old_ms) {
499 /* We cannot find ms->ms by IMSI since we know that it has a
500 * different IMSI */
501 OSMO_ASSERT(old_ms != ms);
502
503 LOGPMS(ms, DRLCMAC, LOGL_NOTICE,
504 "IMSI '%s' was already assigned to another "
505 "MS object: TLLI = 0x%08x, that IMSI will be removed\n",
506 imsi, ms_tlli(old_ms));
507
508 ms_merge_and_clear_ms(ms, old_ms);
509 }
510
511
512 osmo_strlcpy(ms->imsi, imsi, sizeof(ms->imsi));
513}
514
515void ms_set_ta(struct GprsMs *ms, uint8_t ta_)
516{
517 if (ta_ == ms->ta)
518 return;
519
520 if (gsm48_ta_is_valid(ta_)) {
521 LOGP(DRLCMAC, LOGL_INFO,
522 "Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
523 ms_tlli(ms), ms->ta, ta_);
524 ms->ta = ta_;
525 } else
526 LOGP(DRLCMAC, LOGL_NOTICE,
527 "MS object, TLLI = 0x%08x, invalid TA %d rejected (old "
528 "value %d kept)\n", ms_tlli(ms), ta_, ms->ta);
529}
530
531void ms_set_ms_class(struct GprsMs *ms, uint8_t ms_class_)
532{
533 if (ms_class_ == ms->ms_class)
534 return;
535
536 LOGP(DRLCMAC, LOGL_INFO,
537 "Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",
538 ms_tlli(ms), ms->ms_class, ms_class_);
539
540 ms->ms_class = ms_class_;
541}
542
543void ms_set_egprs_ms_class(struct GprsMs *ms, uint8_t ms_class_)
544{
545 if (ms_class_ == ms->egprs_ms_class)
546 return;
547
548 LOGP(DRLCMAC, LOGL_INFO,
549 "Modifying MS object, TLLI = 0x%08x, EGPRS MS class %d -> %d\n",
550 ms_tlli(ms), ms->egprs_ms_class, ms_class_);
551
552 ms->egprs_ms_class = ms_class_;
553
554 if (!bts_max_mcs_ul(ms->bts) || !bts_max_mcs_dl(ms->bts)) {
555 LOGPMS(ms, DRLCMAC, LOGL_DEBUG,
556 "Avoid enabling EGPRS because use of MCS is disabled: ul=%u dl=%u\n",
557 bts_max_mcs_ul(ms->bts), bts_max_mcs_dl(ms->bts));
558 return;
559 }
560
561 if (mcs_is_edge_gmsk(mcs_get_egprs_by_num(bts_max_mcs_ul(ms->bts))) &&
562 mcs_is_edge_gmsk(mcs_get_egprs_by_num(bts_max_mcs_dl(ms->bts))) &&
563 ms_mode(ms) != EGPRS)
564 {
565 ms_set_mode(ms, EGPRS_GMSK);
566 } else {
567 ms_set_mode(ms, EGPRS);
568 }
569 LOGPMS(ms, DRLCMAC, LOGL_INFO, "Enabled EGPRS, mode %s\n", mode_name(ms_mode(ms)));
570}
571
572void ms_update_error_rate(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, int error_rate)
573{
574 struct gprs_rlcmac_bts *bts_;
575 int64_t now;
576 enum CodingScheme max_cs_dl = ms_max_cs_dl(ms);
577
578 OSMO_ASSERT(max_cs_dl);
579 bts_ = bts_data(ms->bts);
580
581 if (error_rate < 0)
582 return;
583
584 now = now_msec();
585
586 /* TODO: Check for TBF direction */
587 /* TODO: Support different CS values for UL and DL */
588
589 ms->nack_rate_dl = error_rate;
590
591 if (error_rate > bts_->cs_adj_upper_limit) {
592 if (mcs_chan_code(ms->current_cs_dl) > 0) {
593 mcs_dec_kind(&ms->current_cs_dl, ms_mode(ms));
594 LOGP(DRLCMACDL, LOGL_INFO,
595 "MS (IMSI %s): High error rate %d%%, "
596 "reducing CS level to %s\n",
597 ms_imsi(ms), error_rate, mcs_name(ms->current_cs_dl));
598 ms->last_cs_not_low = now;
599 }
600 } else if (error_rate < bts_->cs_adj_lower_limit) {
601 if (ms->current_cs_dl < max_cs_dl) {
602 if (now - ms->last_cs_not_low > 1000) {
603 mcs_inc_kind(&ms->current_cs_dl, ms_mode(ms));
604
605 LOGP(DRLCMACDL, LOGL_INFO,
606 "MS (IMSI %s): Low error rate %d%%, "
607 "increasing DL CS level to %s\n",
608 ms_imsi(ms), error_rate,
609 mcs_name(ms->current_cs_dl));
610 ms->last_cs_not_low = now;
611 } else {
612 LOGP(DRLCMACDL, LOGL_DEBUG,
613 "MS (IMSI %s): Low error rate %d%%, "
614 "ignored (within blocking period)\n",
615 ms_imsi(ms), error_rate);
616 }
617 }
618 } else {
619 LOGP(DRLCMACDL, LOGL_DEBUG,
620 "MS (IMSI %s): Medium error rate %d%%, ignored\n",
621 ms_imsi(ms), error_rate);
622 ms->last_cs_not_low = now;
623 }
624}
625
626enum CodingScheme ms_max_cs_ul(const struct GprsMs *ms)
627{
628 OSMO_ASSERT(ms->bts != NULL);
629
630 if (mcs_is_gprs(ms->current_cs_ul)) {
631 if (!bts_max_cs_ul(ms->bts)) {
632 return CS4;
633 }
634
635 return mcs_get_gprs_by_num(bts_max_cs_ul(ms->bts));
636 }
637
638 if (!mcs_is_edge(ms->current_cs_ul))
639 return UNKNOWN;
640
641 if (bts_max_mcs_ul(ms->bts))
642 return mcs_get_egprs_by_num(bts_max_mcs_ul(ms->bts));
643 else if (bts_max_cs_ul(ms->bts))
644 return mcs_get_gprs_by_num(bts_max_cs_ul(ms->bts));
645
646 return MCS4;
647}
648
649void ms_set_current_cs_dl(struct GprsMs *ms, enum CodingScheme scheme)
650{
651 ms->current_cs_dl = scheme;
652}
653
654enum CodingScheme ms_max_cs_dl(const struct GprsMs *ms)
655{
656 OSMO_ASSERT(ms->bts != NULL);
657
658 if (mcs_is_gprs(ms->current_cs_dl)) {
659 if (!bts_max_cs_dl(ms->bts)) {
660 return CS4;
661 }
662
663 return mcs_get_gprs_by_num(bts_max_cs_dl(ms->bts));
664 }
665
666 if (!mcs_is_edge(ms->current_cs_dl))
667 return UNKNOWN;
668
669 if (bts_max_mcs_dl(ms->bts))
670 return mcs_get_egprs_by_num(bts_max_mcs_dl(ms->bts));
671 else if (bts_max_cs_dl(ms->bts))
672 return mcs_get_gprs_by_num(bts_max_cs_dl(ms->bts));
673
674 return MCS4;
675}
676
677void ms_update_cs_ul(struct GprsMs *ms, const struct pcu_l1_meas *meas)
678{
679 struct gprs_rlcmac_bts *bts_;
680 enum CodingScheme max_cs_ul = ms_max_cs_ul(ms);
681
682 int old_link_qual;
683 int low;
684 int high;
685 enum CodingScheme new_cs_ul = ms->current_cs_ul;
686 uint8_t current_cs = mcs_chan_code(ms->current_cs_ul);
687
688 bts_ = bts_data(ms->bts);
689
690 if (!max_cs_ul) {
691 LOGP(DRLCMACMEAS, LOGL_ERROR,
692 "max_cs_ul cannot be derived (current UL CS: %s)\n",
693 mcs_name(ms->current_cs_ul));
694 return;
695 }
696
697 if (!ms->current_cs_ul) {
698 LOGP(DRLCMACMEAS, LOGL_ERROR,
699 "Unable to update UL (M)CS because it's not set: %s\n",
700 mcs_name(ms->current_cs_ul));
701 return;
702 }
703
704 if (!meas->have_link_qual) {
705 LOGP(DRLCMACMEAS, LOGL_ERROR,
706 "Unable to update UL (M)CS %s because we don't have link quality measurements.\n",
707 mcs_name(ms->current_cs_ul));
708 return;
709 }
710
711 if (mcs_is_gprs(ms->current_cs_ul)) {
712 if (current_cs >= MAX_GPRS_CS)
713 current_cs = MAX_GPRS_CS - 1;
714 low = bts_->cs_lqual_ranges[current_cs].low;
715 high = bts_->cs_lqual_ranges[current_cs].high;
716 } else if (mcs_is_edge(ms->current_cs_ul)) {
717 if (current_cs >= MAX_EDGE_MCS)
718 current_cs = MAX_EDGE_MCS - 1;
719 low = bts_->mcs_lqual_ranges[current_cs].low;
720 high = bts_->mcs_lqual_ranges[current_cs].high;
721 } else {
722 LOGP(DRLCMACMEAS, LOGL_ERROR,
723 "Unable to update UL (M)CS because it's neither GPRS nor EDGE: %s\n",
724 mcs_name(ms->current_cs_ul));
725 return;
726 }
727
728 /* To avoid rapid changes of the coding scheme, we also take
729 * the old link quality value into account (if present). */
730 if (ms->l1_meas.have_link_qual)
731 old_link_qual = ms->l1_meas.link_qual;
732 else
733 old_link_qual = meas->link_qual;
734
735 if (meas->link_qual < low && old_link_qual < low)
736 mcs_dec_kind(&new_cs_ul, ms_mode(ms));
737 else if (meas->link_qual > high && old_link_qual > high &&
738 ms->current_cs_ul < max_cs_ul)
739 mcs_inc_kind(&new_cs_ul, ms_mode(ms));
740
741 if (ms->current_cs_ul != new_cs_ul) {
742 LOGPMS(ms, DRLCMACMEAS, LOGL_INFO,
743 "Link quality %ddB (old %ddB) left window [%d, %d], "
744 "modifying uplink CS level: %s -> %s\n",
745 meas->link_qual, old_link_qual,
746 low, high,
747 mcs_name(ms->current_cs_ul), mcs_name(new_cs_ul));
748
749 ms->current_cs_ul = new_cs_ul;
750 }
751}
752
753void ms_update_l1_meas(struct GprsMs *ms, const struct pcu_l1_meas *meas)
754{
755 unsigned i;
756
757 ms_update_cs_ul(ms, meas);
758
759 if (meas->have_rssi)
760 pcu_l1_meas_set_rssi(&ms->l1_meas, meas->rssi);
761 if (meas->have_bto)
762 pcu_l1_meas_set_bto(&ms->l1_meas, meas->bto);
763 if (meas->have_ber)
764 pcu_l1_meas_set_ber(&ms->l1_meas, meas->ber);
765 if (meas->have_link_qual)
766 pcu_l1_meas_set_link_qual(&ms->l1_meas, meas->link_qual);
767
768 if (meas->have_ms_rx_qual)
769 pcu_l1_meas_set_ms_rx_qual(&ms->l1_meas, meas->ms_rx_qual);
770 if (meas->have_ms_c_value)
771 pcu_l1_meas_set_ms_c_value(&ms->l1_meas, meas->ms_c_value);
772 if (meas->have_ms_sign_var)
773 pcu_l1_meas_set_ms_sign_var(&ms->l1_meas, meas->ms_sign_var);
774
775 if (meas->have_ms_i_level) {
776 for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
777 if (meas->ts[i].have_ms_i_level)
778 pcu_l1_meas_set_ms_i_level(&ms->l1_meas, i, meas->ts[i].ms_i_level);
779 else
780 ms->l1_meas.ts[i].have_ms_i_level = 0;
781 }
782 }
783}
784
785enum CodingScheme ms_current_cs_dl(const struct GprsMs *ms)
786{
787 enum CodingScheme cs = ms->current_cs_dl;
788 size_t unencoded_octets;
789
790 if (!ms->bts)
791 return cs;
792
793 unencoded_octets = llc_queue_octets(&ms->llc_queue);
794
795 /* If the DL TBF is active, add number of unencoded chunk octets */
796 if (ms->dl_tbf)
797 unencoded_octets += llc_chunk_size(tbf_llc((struct gprs_rlcmac_tbf *)ms->dl_tbf));
798
799 /* There are many unencoded octets, don't reduce */
800 if (unencoded_octets >= bts_data(ms->bts)->cs_downgrade_threshold)
801 return cs;
802
803 /* RF conditions are good, don't reduce */
804 if (ms->nack_rate_dl < bts_data(ms->bts)->cs_adj_lower_limit)
805 return cs;
806
807 /* The throughput would probably be better if the CS level was reduced */
808 mcs_dec_kind(&cs, ms_mode(ms));
809
810 /* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
811 if (cs == CS2)
812 mcs_dec_kind(&cs, ms_mode(ms));
813
814 return cs;
815}
816
817int ms_first_common_ts(const struct GprsMs *ms)
818{
819 if (ms->dl_tbf)
820 return tbf_first_common_ts((struct gprs_rlcmac_tbf *)ms->dl_tbf);
821
822 if (ms->ul_tbf)
823 return tbf_first_common_ts((struct gprs_rlcmac_tbf *)ms->ul_tbf);
824
825 return -1;
826}
827
828uint8_t ms_dl_slots(const struct GprsMs *ms)
829{
830 uint8_t slots = 0;
831
832 if (ms->dl_tbf)
833 slots |= tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
834
835 if (ms->ul_tbf)
836 slots |= tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);
837
838 return slots;
839}
840
841uint8_t ms_ul_slots(const struct GprsMs *ms)
842{
843 uint8_t slots = 0;
844
845 if (ms->dl_tbf)
846 slots |= tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
847
848 if (ms->ul_tbf)
849 slots |= tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);
850
851 return slots;
852}
853
854uint8_t ms_current_pacch_slots(const struct GprsMs *ms)
855{
856 uint8_t slots = 0;
857
858 bool is_dl_active = ms->dl_tbf && tbf_is_tfi_assigned((struct gprs_rlcmac_tbf *)ms->dl_tbf);
859 bool is_ul_active = ms->ul_tbf && tbf_is_tfi_assigned((struct gprs_rlcmac_tbf *)ms->ul_tbf);
860
861 if (!is_dl_active && !is_ul_active)
862 return 0;
863
864 /* see TS 44.060, 8.1.1.2.2 */
865 if (is_dl_active && !is_ul_active)
866 slots = tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
867 else if (!is_dl_active && is_ul_active)
868 slots = tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);
869 else
870 slots = tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf) &
871 tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
872
873 /* Assume a multislot class 1 device */
874 /* TODO: For class 2 devices, this could be removed */
875 slots = pcu_lsb(slots);
876
877 return slots;
878}
879
880void ms_set_reserved_slots(struct GprsMs *ms, struct gprs_rlcmac_trx *trx,
881 uint8_t ul_slots, uint8_t dl_slots)
882{
883 if (ms->current_trx) {
884 bts_trx_unreserve_slots(ms->current_trx, GPRS_RLCMAC_DL_TBF,
885 ms->reserved_dl_slots);
886 bts_trx_unreserve_slots(ms->current_trx, GPRS_RLCMAC_UL_TBF,
887 ms->reserved_ul_slots);
888 ms->reserved_dl_slots = 0;
889 ms->reserved_ul_slots = 0;
890 }
891 ms->current_trx = trx;
892 if (trx) {
893 ms->reserved_dl_slots = dl_slots;
894 ms->reserved_ul_slots = ul_slots;
895 bts_trx_reserve_slots(ms->current_trx, GPRS_RLCMAC_DL_TBF,
896 ms->reserved_dl_slots);
897 bts_trx_reserve_slots(ms->current_trx, GPRS_RLCMAC_UL_TBF,
898 ms->reserved_ul_slots);
899 }
900}
901
902struct gprs_rlcmac_tbf *ms_tbf(const struct GprsMs *ms, enum gprs_rlcmac_tbf_direction dir)
903{
904 switch (dir) {
905 case GPRS_RLCMAC_DL_TBF: return (struct gprs_rlcmac_tbf *)ms->dl_tbf;
906 case GPRS_RLCMAC_UL_TBF: return (struct gprs_rlcmac_tbf *)ms->ul_tbf;
907 }
908
909 return NULL;
910}