blob: 357470b592ba708b9855f46b85f77d2f97efccc8 [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.
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010015 */
16
17
18#include "gprs_ms.h"
19#include "bts.h"
20#include "tbf.h"
21#include "tbf_ul.h"
22#include "gprs_debug.h"
23#include "gprs_codel.h"
24#include "pcu_utils.h"
Pau Espin Pedrolc0a250d2021-01-21 18:46:13 +010025#include "nacc_fsm.h"
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +020026#include "tbf_ul_ack_fsm.h"
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010027
28#include <time.h>
29
30#include <osmocom/core/talloc.h>
31#include <osmocom/core/utils.h>
32#include <osmocom/core/timer.h>
33#include <osmocom/gsm/protocol/gsm_04_08.h>
34#include <osmocom/gsm/gsm48.h>
35#include <osmocom/core/logging.h>
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +010036#include <osmocom/core/stats.h>
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010037#include "coding_scheme.h"
38
39#define GPRS_CODEL_SLOW_INTERVAL_MS 4000
40
41extern void *tall_pcu_ctx;
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +010042static unsigned int next_ms_ctr_group_id;
43
44static const struct rate_ctr_desc ms_ctr_description[] = {
45 [MS_CTR_DL_CTRL_MSG_SCHED] = { "ms:dl_ctrl_msg_sched", "Amount of DL CTRL messages scheduled" },
46};
47
Pau Espin Pedrolf5a251b2021-01-12 20:57:56 +010048static const struct rate_ctr_group_desc ms_ctrg_desc = {
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +010049 .group_name_prefix = "pcu:ms",
50 .group_description = "MS Statistics",
51 .class_id = OSMO_STATS_CLASS_SUBSCRIBER,
52 .num_ctr = ARRAY_SIZE(ms_ctr_description),
53 .ctr_desc = ms_ctr_description,
54};
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010055
56static int64_t now_msec()
57{
58 struct timespec ts;
59 osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
60
61 return (int64_t)(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
62}
63
Pau Espin Pedrol403e0482023-04-17 20:28:10 +020064static void ms_update_status(struct GprsMs *ms);
65
66static int ms_use_cb(struct osmo_use_count_entry *e, int32_t old_use_count, const char *file, int line)
67{
68 struct GprsMs *ms = e->use_count->talloc_object;
69 int32_t total;
70 int level;
71 char buf[1024];
72
73 if (!e->use)
74 return -EINVAL;
75
76 total = osmo_use_count_total(&ms->use_count);
77
78 if (total == 0
79 || (total == 1 && old_use_count == 0 && e->count == 1))
80 level = LOGL_INFO;
81 else
82 level = LOGL_DEBUG;
83
84
85 LOGPSRC(DRLCMAC, level, file, line, "%s: %s %s: now used by %s\n",
86 ms_name(ms),
87 (e->count - old_use_count) > 0 ? "+" : "-", e->use,
88 (osmo_use_count_to_str_buf(buf, sizeof(buf), &ms->use_count), buf));
89
90 if (e->count < 0)
91 return -ERANGE;
92
93 if (total == 0)
94 ms_update_status(ms);
95 return 0;
96}
97
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +010098void gprs_default_cb_ms_idle(struct GprsMs *ms)
99{
Pau Espin Pedrol9da06862023-04-17 19:00:04 +0200100 if (ms_is_idle(ms))
101 talloc_free(ms);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100102}
103
104void gprs_default_cb_ms_active(struct GprsMs *ms)
105{
106 /* do nothing */
107}
108
109static struct gpr_ms_callback gprs_default_cb = {
110 .ms_idle = gprs_default_cb_ms_idle,
111 .ms_active = gprs_default_cb_ms_active,
112};
113
Pau Espin Pedrol4fe09012021-03-03 17:30:50 +0100114static void ms_release_timer_cb(void *data)
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100115{
116 struct GprsMs *ms = (struct GprsMs *) data;
Pau Espin Pedrol4fe09012021-03-03 17:30:50 +0100117 LOGPMS(ms, DRLCMAC, LOGL_INFO, "Release timer expired\n");
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100118
119 if (ms->timer.data) {
120 ms->timer.data = NULL;
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200121 ms_unref(ms, MS_USE_RELEASE_TIMER);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100122 }
123}
124
Pau Espin Pedrol14beef62022-10-26 19:44:07 +0200125static void ms_llc_timer_cb(void *_ms)
126{
127 struct GprsMs *ms = _ms;
128 struct gprs_rlcmac_dl_tbf *dl_tbf = ms_dl_tbf(ms);
129
130 if (!dl_tbf)
131 return;
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200132 if (tbf_state(dl_tbf_as_tbf_const(dl_tbf)) != TBF_ST_FLOW)
Pau Espin Pedrol14beef62022-10-26 19:44:07 +0200133 return;
134
Pau Espin Pedrolbd1f01f2022-10-27 15:19:39 +0200135 LOGPTBFDL(dl_tbf, LOGL_DEBUG, "LLC receive timeout, requesting DL ACK\n");
Pau Espin Pedrol14beef62022-10-26 19:44:07 +0200136
Pau Espin Pedrol8fa3e062022-10-28 17:38:52 +0200137 dl_tbf_request_dl_ack(dl_tbf);
Pau Espin Pedrol14beef62022-10-26 19:44:07 +0200138}
139
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100140static int ms_talloc_destructor(struct GprsMs *ms);
Pau Espin Pedrolf80cc5b2023-04-17 14:25:51 +0200141struct GprsMs *ms_alloc(struct gprs_rlcmac_bts *bts)
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100142{
143 struct GprsMs *ms = talloc_zero(tall_pcu_ctx, struct GprsMs);
Pau Espin Pedrolb4987462022-04-01 17:21:08 +0200144 OSMO_ASSERT(bts);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100145
146 talloc_set_destructor(ms, ms_talloc_destructor);
147
Pau Espin Pedrolfe7aee92023-04-17 18:23:56 +0200148 llist_add(&ms->list, &bts->ms_list);
Pau Espin Pedrol9da06862023-04-17 19:00:04 +0200149 bts_stat_item_inc(bts, STAT_MS_PRESENT);
Pau Espin Pedrolfe7aee92023-04-17 18:23:56 +0200150
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100151 ms->bts = bts;
152 ms->cb = gprs_default_cb;
Pau Espin Pedrolf80cc5b2023-04-17 14:25:51 +0200153 ms->tlli = GSM_RESERVED_TMSI;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100154 ms->new_ul_tlli = GSM_RESERVED_TMSI;
155 ms->new_dl_tlli = GSM_RESERVED_TMSI;
156 ms->ta = GSM48_TA_INVALID;
157 ms->current_cs_ul = UNKNOWN;
158 ms->current_cs_dl = UNKNOWN;
159 ms->is_idle = true;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100160 INIT_LLIST_HEAD(&ms->old_tbfs);
161
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200162 ms->use_count = (struct osmo_use_count){
163 .talloc_object = ms,
164 .use_cb = ms_use_cb,
165 };
166
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100167 int codel_interval = LLC_CODEL_USE_DEFAULT;
168
Pau Espin Pedrolf80cc5b2023-04-17 14:25:51 +0200169 LOGP(DRLCMAC, LOGL_INFO, "Creating MS object\n");
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100170
171 ms->imsi[0] = '\0';
Pau Espin Pedrolc7802d92022-05-09 16:07:52 +0200172 osmo_timer_setup(&ms->timer, ms_release_timer_cb, NULL);
Pau Espin Pedrol6b1e9512022-04-04 13:45:56 +0200173 llc_queue_init(&ms->llc_queue, ms);
Pau Espin Pedrol14beef62022-10-26 19:44:07 +0200174 memset(&ms->llc_timer, 0, sizeof(ms->llc_timer));
175 osmo_timer_setup(&ms->llc_timer, ms_llc_timer_cb, ms);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100176
177 ms_set_mode(ms, GPRS);
178
Pau Espin Pedrolb4987462022-04-01 17:21:08 +0200179 codel_interval = the_pcu->vty.llc_codel_interval_msec;
Pau Espin Pedrol6b1e9512022-04-04 13:45:56 +0200180 if (codel_interval == LLC_CODEL_USE_DEFAULT)
181 codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS;
182 llc_queue_set_codel_interval(&ms->llc_queue, codel_interval);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100183
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100184 ms->last_cs_not_low = now_msec();
185 ms->app_info_pending = false;
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +0100186
187 ms->ctrs = rate_ctr_group_alloc(ms, &ms_ctrg_desc, next_ms_ctr_group_id++);
188 if (!ms->ctrs)
189 goto free_ret;
190
Pau Espin Pedrol9da06862023-04-17 19:00:04 +0200191 ms_set_timeout(ms, osmo_tdef_get(bts->pcu->T_defs, -2030, OSMO_TDEF_S, -1));
192
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100193 return ms;
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +0100194free_ret:
195 talloc_free(ms);
196 return NULL;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100197}
198
199static int ms_talloc_destructor(struct GprsMs *ms)
200{
201 struct llist_item *pos, *tmp;
202
Pau Espin Pedrol11f01102021-03-03 20:37:38 +0100203 LOGPMS(ms, DRLCMAC, LOGL_INFO, "Destroying MS object\n");
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100204
Pau Espin Pedrol9da06862023-04-17 19:00:04 +0200205 bts_stat_item_dec(ms->bts, STAT_MS_PRESENT);
Pau Espin Pedrolfe7aee92023-04-17 18:23:56 +0200206 llist_del(&ms->list);
207
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100208 ms_set_reserved_slots(ms, NULL, 0, 0);
209
Vadim Yanitskiye33c2362022-07-22 03:44:44 +0700210 osmo_timer_del(&ms->timer);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100211
212 if (ms->ul_tbf) {
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200213 tbf_set_ms(ul_tbf_as_tbf(ms->ul_tbf), NULL);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100214 ms->ul_tbf = NULL;
215 }
216
217 if (ms->dl_tbf) {
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200218 tbf_set_ms(dl_tbf_as_tbf(ms->dl_tbf), NULL);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100219 ms->dl_tbf = NULL;
220 }
221
222 llist_for_each_entry_safe(pos, tmp, &ms->old_tbfs, list) {
223 struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)pos->entry;
224 tbf_set_ms(tbf, NULL);
225 }
226
227 llc_queue_clear(&ms->llc_queue, ms->bts);
Pau Espin Pedrol14beef62022-10-26 19:44:07 +0200228 osmo_timer_del(&ms->llc_timer);
Pau Espin Pedrolbed48cc2021-01-11 17:32:18 +0100229
230 if (ms->ctrs)
231 rate_ctr_group_free(ms->ctrs);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100232 return 0;
233}
234
235
236void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb)
237{
238 if (cb)
239 ms->cb = *cb;
240 else
241 ms->cb = gprs_default_cb;
242}
243
244static void ms_update_status(struct GprsMs *ms)
245{
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200246 if (osmo_use_count_total(&ms->use_count) > 0)
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100247 return;
248
249 if (ms_is_idle(ms) && !ms->is_idle) {
250 ms->is_idle = true;
251 ms->cb.ms_idle(ms);
252 /* this can be deleted by now, do not access it */
253 return;
254 }
255
256 if (!ms_is_idle(ms) && ms->is_idle) {
257 ms->is_idle = false;
258 ms->cb.ms_active(ms);
259 }
260}
261
Pau Espin Pedrol4fe09012021-03-03 17:30:50 +0100262static void ms_release_timer_start(struct GprsMs *ms)
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100263{
Pau Espin Pedrol14379ef2023-04-17 20:43:26 +0200264 /* Immediate free():
265 * Skip delaying free() through release timer if delay is configured to be 0.
266 * This is useful for synced freed during unit tests.
267 */
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100268 if (ms->delay == 0)
269 return;
270
Pau Espin Pedrol14379ef2023-04-17 20:43:26 +0200271 /* Immediate free():
272 * Skip delaying free() through release timer if TMSI is not
273 * known, since those cannot really be reused.
274 */
275 if (ms_tlli(ms) == GSM_RESERVED_TMSI)
276 return;
277
Pau Espin Pedrol4fe09012021-03-03 17:30:50 +0100278 LOGPMS(ms, DRLCMAC, LOGL_DEBUG, "Schedule MS release in %u secs\n", ms->delay);
279
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200280 if (!ms->timer.data) {
281 ms_ref(ms, MS_USE_RELEASE_TIMER);
282 ms->timer.data = ms;
283 }
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100284
285 osmo_timer_schedule(&ms->timer, ms->delay, 0);
286}
287
Pau Espin Pedrol4fe09012021-03-03 17:30:50 +0100288static void ms_release_timer_stop(struct GprsMs *ms)
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100289{
290 if (!ms->timer.data)
291 return;
292
Pau Espin Pedrol4fe09012021-03-03 17:30:50 +0100293 LOGPMS(ms, DRLCMAC, LOGL_DEBUG, "Cancel scheduled MS release\n");
294
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100295 osmo_timer_del(&ms->timer);
296 ms->timer.data = NULL;
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200297 ms_unref(ms, MS_USE_RELEASE_TIMER);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100298}
299
300void ms_set_mode(struct GprsMs *ms, enum mcs_kind mode)
301{
302 ms->mode = mode;
303
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100304 switch (ms->mode) {
305 case GPRS:
306 if (!mcs_is_gprs(ms->current_cs_ul)) {
307 ms->current_cs_ul = mcs_get_gprs_by_num(
Pau Espin Pedrol2182e622021-01-14 16:48:38 +0100308 ms->bts->initial_cs_ul);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100309 if (!mcs_is_valid(ms->current_cs_ul))
310 ms->current_cs_ul = CS1;
311 }
312 if (!mcs_is_gprs(ms->current_cs_dl)) {
313 ms->current_cs_dl = mcs_get_gprs_by_num(
Pau Espin Pedrol2182e622021-01-14 16:48:38 +0100314 ms->bts->initial_cs_dl);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100315 if (!mcs_is_valid(ms->current_cs_dl))
316 ms->current_cs_dl = CS1;
317 }
318 break;
319
320 case EGPRS_GMSK:
Pau Espin Pedrol7bb8cd62021-01-25 15:08:35 +0100321 if (!mcs_is_edge_gmsk(ms->current_cs_ul)) {
322 ms->current_cs_ul = mcs_get_egprs_by_num(
323 ms->bts->initial_mcs_ul);
324 if (!mcs_is_valid(ms->current_cs_ul))
325 ms->current_cs_ul = MCS1;
326 }
327 if (!mcs_is_edge_gmsk(ms->current_cs_dl)) {
328 ms->current_cs_dl = mcs_get_egprs_by_num(
329 ms->bts->initial_mcs_dl);
330 if (!mcs_is_valid(ms->current_cs_dl))
331 ms->current_cs_dl = MCS1;
332 }
333 break;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100334 case EGPRS:
335 if (!mcs_is_edge(ms->current_cs_ul)) {
336 ms->current_cs_ul = mcs_get_egprs_by_num(
Pau Espin Pedrol2182e622021-01-14 16:48:38 +0100337 ms->bts->initial_mcs_ul);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100338 if (!mcs_is_valid(ms->current_cs_ul))
339 ms->current_cs_ul = MCS1;
340 }
341 if (!mcs_is_edge(ms->current_cs_dl)) {
342 ms->current_cs_dl = mcs_get_egprs_by_num(
Pau Espin Pedrol2182e622021-01-14 16:48:38 +0100343 ms->bts->initial_mcs_dl);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100344 if (!mcs_is_valid(ms->current_cs_dl))
345 ms->current_cs_dl = MCS1;
346 }
347 break;
348 }
349}
350
351static void ms_attach_ul_tbf(struct GprsMs *ms, struct gprs_rlcmac_ul_tbf *tbf)
352{
353 if (ms->ul_tbf == tbf)
354 return;
355
Pau Espin Pedrol11f01102021-03-03 20:37:38 +0100356 LOGPMS(ms, DRLCMAC, LOGL_INFO, "Attaching UL TBF: %s\n", tbf_name((struct gprs_rlcmac_tbf *)tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100357
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200358 ms_ref(ms, __func__);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100359
360 if (ms->ul_tbf)
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200361 llist_add_tail(tbf_ms_list(ul_tbf_as_tbf(ms->ul_tbf)), &ms->old_tbfs);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100362
363 ms->ul_tbf = tbf;
364
Pau Espin Pedrol3ea467d2023-04-18 16:33:34 +0200365 ms_release_timer_stop(ms);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100366
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200367 ms_unref(ms, __func__);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100368}
369
370static void ms_attach_dl_tbf(struct GprsMs *ms, struct gprs_rlcmac_dl_tbf *tbf)
371{
372 if (ms->dl_tbf == tbf)
373 return;
374
Pau Espin Pedrol11f01102021-03-03 20:37:38 +0100375 LOGPMS(ms, DRLCMAC, LOGL_INFO, "Attaching DL TBF: %s\n", tbf_name((struct gprs_rlcmac_tbf *)tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100376
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200377 ms_ref(ms, __func__);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100378
379 if (ms->dl_tbf)
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200380 llist_add_tail(tbf_ms_list(dl_tbf_as_tbf(ms->dl_tbf)), &ms->old_tbfs);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100381
382 ms->dl_tbf = tbf;
383
Pau Espin Pedrol3ea467d2023-04-18 16:33:34 +0200384 ms_release_timer_stop(ms);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100385
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200386 ms_unref(ms, __func__);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100387}
388
389void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)
390{
Pau Espin Pedrol3ea467d2023-04-18 16:33:34 +0200391 OSMO_ASSERT(ms);
392 OSMO_ASSERT(tbf);
393
Pau Espin Pedrolb5fece92021-08-23 16:58:04 +0200394 if (tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF)
Pau Espin Pedrolcc30b052022-10-27 15:25:55 +0200395 ms_attach_dl_tbf(ms, tbf_as_dl_tbf(tbf));
Pau Espin Pedrolb5fece92021-08-23 16:58:04 +0200396 else
Pau Espin Pedrolcc30b052022-10-27 15:25:55 +0200397 ms_attach_ul_tbf(ms, tbf_as_ul_tbf(tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100398}
399
400void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)
401{
402 if (tbf == (struct gprs_rlcmac_tbf *)(ms->ul_tbf)) {
403 ms->ul_tbf = NULL;
404 } else if (tbf == (struct gprs_rlcmac_tbf *)(ms->dl_tbf)) {
405 ms->dl_tbf = NULL;
406 } else {
407 bool found = false;
408
409 struct llist_item *pos, *tmp;
410 llist_for_each_entry_safe(pos, tmp, &ms->old_tbfs, list) {
411 struct gprs_rlcmac_tbf *tmp_tbf = (struct gprs_rlcmac_tbf *)pos->entry;
412 if (tmp_tbf == tbf) {
413 llist_del(&pos->list);
414 found = true;
415 break;
416 }
417 }
418
419 /* Protect against recursive calls via set_ms() */
420 if (!found)
421 return;
422 }
423
Pau Espin Pedrol11f01102021-03-03 20:37:38 +0100424 LOGPMS(ms, DRLCMAC, LOGL_INFO, "Detaching TBF: %s\n",
425 tbf_name(tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100426
427 if (tbf_ms(tbf) == ms)
428 tbf_set_ms(tbf, NULL);
429
430 if (!ms->dl_tbf && !ms->ul_tbf) {
431 ms_set_reserved_slots(ms, NULL, 0, 0);
Pau Espin Pedrol9935d0d2022-12-13 18:29:25 +0100432 ms->first_common_ts = NULL;
Pau Espin Pedrol14379ef2023-04-17 20:43:26 +0200433 ms_release_timer_start(ms);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100434 }
435
436 ms_update_status(ms);
437}
438
439void ms_reset(struct GprsMs *ms)
440{
Pau Espin Pedrol11f01102021-03-03 20:37:38 +0100441 LOGPMS(ms, DRLCMAC, LOGL_INFO, "Clearing MS object\n");
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100442
Pau Espin Pedrol4fe09012021-03-03 17:30:50 +0100443 ms_release_timer_stop(ms);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100444
445 ms->tlli = GSM_RESERVED_TMSI;
446 ms->new_dl_tlli = ms->tlli;
447 ms->new_ul_tlli = ms->tlli;
448 ms->imsi[0] = '\0';
449}
450
Pau Espin Pedrol8abe13c2022-10-21 18:49:48 +0200451/* This function should be called on the MS object of a TBF each time an RLCMAC
452 * block is received for it with TLLI information.
453 * Besides updating the TLLI field on the MS object, it also seeks for other MS
454 * objects in the store and merges them into the current MS object. The MS
455 * duplication happened because we don't learn the TLLI of the created TBF until
456 * a later point. */
457void ms_update_announced_tlli(struct GprsMs *ms, uint32_t tlli)
458{
459 struct GprsMs *old_ms = NULL;
460
461 if (tlli == GSM_RESERVED_TMSI)
462 return;
463
464 /* When the TLLI does not match the ms, check if there is another
465 * MS object that belongs to that TLLI and if yes make sure one of them
466 * gets deleted. */
467 if (!ms_check_tlli(ms, tlli))
Pau Espin Pedroleb0a0522023-04-17 16:33:35 +0200468 old_ms = bts_get_ms_by_tlli(ms->bts, tlli, GSM_RESERVED_TMSI);
Pau Espin Pedrol8abe13c2022-10-21 18:49:48 +0200469
470 ms_set_tlli(ms, tlli);
471
472 if (old_ms)
473 ms_merge_and_clear_ms(ms, old_ms);
474 /* old_ms may no longer be available here */
475}
476
Pau Espin Pedrol32416fd2022-10-31 12:55:03 +0100477/* Merge 'old_ms' object into 'ms' object.
478 * 'old_ms' may be freed during the call to this function, don't use the pointer to it afterwards */
479void ms_merge_and_clear_ms(struct GprsMs *ms, struct GprsMs *old_ms)
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100480{
Pau Espin Pedrol32416fd2022-10-31 12:55:03 +0100481 char old_ms_name[128];
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100482 OSMO_ASSERT(old_ms != ms);
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200483 ms_ref(old_ms, __func__);
Pau Espin Pedrol32416fd2022-10-31 12:55:03 +0100484
485 ms_name_buf(old_ms, old_ms_name, sizeof(old_ms_name));
486
487 LOGPMS(ms, DRLCMAC, LOGL_INFO, "Merge MS: %s\n", old_ms_name);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100488
489 if (strlen(ms_imsi(ms)) == 0 && strlen(ms_imsi(old_ms)) != 0)
490 osmo_strlcpy(ms->imsi, ms_imsi(old_ms), sizeof(ms->imsi));
491
492 if (!ms_ms_class(ms) && ms_ms_class(old_ms))
493 ms_set_ms_class(ms, ms_ms_class(old_ms));
494
495 if (!ms_egprs_ms_class(ms) && ms_egprs_ms_class(old_ms))
496 ms_set_egprs_ms_class(ms, ms_egprs_ms_class(old_ms));
497
498 llc_queue_move_and_merge(&ms->llc_queue, &old_ms->llc_queue);
499
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100500 /* Clean up the old MS object */
501 /* TODO: Use timer? */
502 if (ms_ul_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms), T_MAX))
503 tbf_free((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms));
504 if (ms_dl_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms), T_MAX))
505 tbf_free((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms));
506
Pau Espin Pedrol32416fd2022-10-31 12:55:03 +0100507 ms_reset(old_ms);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100508
Pau Espin Pedrol403e0482023-04-17 20:28:10 +0200509 ms_unref(old_ms, __func__);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100510}
511
Pau Espin Pedrol57843c52022-11-03 13:35:19 +0100512/* Apply changes to the TLLI directly, used interally by functions below: */
513static void ms_apply_tlli_change(struct GprsMs *ms, uint32_t tlli)
514{
515 ms->tlli = tlli;
516 ms->new_dl_tlli = GSM_RESERVED_TMSI;
517 ms->new_ul_tlli = GSM_RESERVED_TMSI;
518
519 /* Update TBF FSM names: */
520 if (ms->ul_tbf)
521 tbf_update_state_fsm_name(ul_tbf_as_tbf(ms->ul_tbf));
522 if (ms->dl_tbf)
523 tbf_update_state_fsm_name(dl_tbf_as_tbf(ms->dl_tbf));
524}
525
Pau Espin Pedrol0b5997e2022-10-21 14:10:41 +0200526/* Set/update the MS object TLLI based on knowledge gained from the MS side (Uplink direction) */
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100527void ms_set_tlli(struct GprsMs *ms, uint32_t tlli)
528{
529 if (tlli == ms->tlli || tlli == ms->new_ul_tlli)
530 return;
531
532 if (tlli != ms->new_dl_tlli) {
533 LOGP(DRLCMAC, LOGL_INFO,
534 "Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
535 "not yet confirmed\n",
536 ms_tlli(ms), tlli);
537 ms->new_ul_tlli = tlli;
538 return;
539 }
540
541 LOGP(DRLCMAC, LOGL_INFO,
542 "Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
543 "already confirmed partly\n",
544 ms->tlli, tlli);
545
Pau Espin Pedrol57843c52022-11-03 13:35:19 +0100546 ms_apply_tlli_change(ms, tlli);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100547}
548
Pau Espin Pedrol0b5997e2022-10-21 14:10:41 +0200549/* Set/update the MS object TLLI based on knowledge gained from the SGSN side (Downlink direction) */
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100550bool ms_confirm_tlli(struct GprsMs *ms, uint32_t tlli)
551{
552 if (tlli == ms->tlli || tlli == ms->new_dl_tlli)
553 return false;
554
555 if (tlli != ms->new_ul_tlli) {
556 /* The MS has not sent a message with the new TLLI, which may
557 * happen according to the spec [TODO: add reference]. */
558
559 LOGP(DRLCMAC, LOGL_INFO,
560 "The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
561 "partly confirmed\n", tlli);
562 /* Use the network's idea of TLLI as candidate, this does not
563 * change the result value of tlli() */
564 ms->new_dl_tlli = tlli;
565 return false;
566 }
567
568 LOGP(DRLCMAC, LOGL_INFO,
569 "Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
570
Pau Espin Pedrol57843c52022-11-03 13:35:19 +0100571 ms_apply_tlli_change(ms, tlli);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100572
573 return true;
574}
575
576void ms_set_imsi(struct GprsMs *ms, const char *imsi)
577{
578 if (!imsi) {
579 LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");
580 return;
581 }
582
583 if (imsi[0] && strlen(imsi) < 3) {
584 LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",
585 imsi);
586 return;
587 }
588
589 if (strcmp(imsi, ms->imsi) == 0)
590 return;
591
592 LOGP(DRLCMAC, LOGL_INFO,
593 "Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",
594 ms_tlli(ms), ms->imsi, imsi);
595
Pau Espin Pedrolcde18c52023-04-17 18:16:48 +0200596 struct GprsMs *old_ms = bts_get_ms_by_imsi(ms->bts, imsi);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100597 /* Check if we are going to store a different MS object with already
598 existing IMSI. This is probably a bug in code calling this function,
599 since it should take care of this explicitly */
600 if (old_ms) {
601 /* We cannot find ms->ms by IMSI since we know that it has a
602 * different IMSI */
603 OSMO_ASSERT(old_ms != ms);
604
605 LOGPMS(ms, DRLCMAC, LOGL_NOTICE,
606 "IMSI '%s' was already assigned to another "
607 "MS object: TLLI = 0x%08x, that IMSI will be removed\n",
608 imsi, ms_tlli(old_ms));
609
610 ms_merge_and_clear_ms(ms, old_ms);
Pau Espin Pedrolb8ff74b2022-10-31 12:58:46 +0100611 /* old_ms may no longer be available here */
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100612 }
613
Pau Espin Pedrol57843c52022-11-03 13:35:19 +0100614 /* Store the new IMSI: */
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100615 osmo_strlcpy(ms->imsi, imsi, sizeof(ms->imsi));
Pau Espin Pedrol57843c52022-11-03 13:35:19 +0100616
617 /* Update TBF FSM names: */
618 if (ms->ul_tbf)
619 tbf_update_state_fsm_name(ul_tbf_as_tbf(ms->ul_tbf));
620 if (ms->dl_tbf)
621 tbf_update_state_fsm_name(dl_tbf_as_tbf(ms->dl_tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100622}
623
624void ms_set_ta(struct GprsMs *ms, uint8_t ta_)
625{
626 if (ta_ == ms->ta)
627 return;
628
629 if (gsm48_ta_is_valid(ta_)) {
630 LOGP(DRLCMAC, LOGL_INFO,
631 "Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
632 ms_tlli(ms), ms->ta, ta_);
633 ms->ta = ta_;
634 } else
635 LOGP(DRLCMAC, LOGL_NOTICE,
636 "MS object, TLLI = 0x%08x, invalid TA %d rejected (old "
637 "value %d kept)\n", ms_tlli(ms), ta_, ms->ta);
638}
639
640void ms_set_ms_class(struct GprsMs *ms, uint8_t ms_class_)
641{
642 if (ms_class_ == ms->ms_class)
643 return;
644
645 LOGP(DRLCMAC, LOGL_INFO,
646 "Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",
647 ms_tlli(ms), ms->ms_class, ms_class_);
648
649 ms->ms_class = ms_class_;
650}
651
652void ms_set_egprs_ms_class(struct GprsMs *ms, uint8_t ms_class_)
653{
654 if (ms_class_ == ms->egprs_ms_class)
655 return;
656
657 LOGP(DRLCMAC, LOGL_INFO,
658 "Modifying MS object, TLLI = 0x%08x, EGPRS MS class %d -> %d\n",
659 ms_tlli(ms), ms->egprs_ms_class, ms_class_);
660
661 ms->egprs_ms_class = ms_class_;
662
663 if (!bts_max_mcs_ul(ms->bts) || !bts_max_mcs_dl(ms->bts)) {
664 LOGPMS(ms, DRLCMAC, LOGL_DEBUG,
665 "Avoid enabling EGPRS because use of MCS is disabled: ul=%u dl=%u\n",
666 bts_max_mcs_ul(ms->bts), bts_max_mcs_dl(ms->bts));
667 return;
668 }
669
670 if (mcs_is_edge_gmsk(mcs_get_egprs_by_num(bts_max_mcs_ul(ms->bts))) &&
671 mcs_is_edge_gmsk(mcs_get_egprs_by_num(bts_max_mcs_dl(ms->bts))) &&
672 ms_mode(ms) != EGPRS)
673 {
674 ms_set_mode(ms, EGPRS_GMSK);
675 } else {
676 ms_set_mode(ms, EGPRS);
677 }
678 LOGPMS(ms, DRLCMAC, LOGL_INFO, "Enabled EGPRS, mode %s\n", mode_name(ms_mode(ms)));
679}
680
681void ms_update_error_rate(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, int error_rate)
682{
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100683 int64_t now;
684 enum CodingScheme max_cs_dl = ms_max_cs_dl(ms);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100685 OSMO_ASSERT(max_cs_dl);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100686
687 if (error_rate < 0)
688 return;
689
690 now = now_msec();
691
692 /* TODO: Check for TBF direction */
693 /* TODO: Support different CS values for UL and DL */
694
695 ms->nack_rate_dl = error_rate;
696
Pau Espin Pedrole8dcf642021-01-14 13:17:01 +0100697 if (error_rate > the_pcu->vty.cs_adj_upper_limit) {
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100698 if (mcs_chan_code(ms->current_cs_dl) > 0) {
699 mcs_dec_kind(&ms->current_cs_dl, ms_mode(ms));
700 LOGP(DRLCMACDL, LOGL_INFO,
701 "MS (IMSI %s): High error rate %d%%, "
702 "reducing CS level to %s\n",
703 ms_imsi(ms), error_rate, mcs_name(ms->current_cs_dl));
704 ms->last_cs_not_low = now;
705 }
Pau Espin Pedrole8dcf642021-01-14 13:17:01 +0100706 } else if (error_rate < the_pcu->vty.cs_adj_lower_limit) {
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100707 if (ms->current_cs_dl < max_cs_dl) {
708 if (now - ms->last_cs_not_low > 1000) {
709 mcs_inc_kind(&ms->current_cs_dl, ms_mode(ms));
710
711 LOGP(DRLCMACDL, LOGL_INFO,
712 "MS (IMSI %s): Low error rate %d%%, "
713 "increasing DL CS level to %s\n",
714 ms_imsi(ms), error_rate,
715 mcs_name(ms->current_cs_dl));
716 ms->last_cs_not_low = now;
717 } else {
718 LOGP(DRLCMACDL, LOGL_DEBUG,
719 "MS (IMSI %s): Low error rate %d%%, "
720 "ignored (within blocking period)\n",
721 ms_imsi(ms), error_rate);
722 }
723 }
724 } else {
725 LOGP(DRLCMACDL, LOGL_DEBUG,
726 "MS (IMSI %s): Medium error rate %d%%, ignored\n",
727 ms_imsi(ms), error_rate);
728 ms->last_cs_not_low = now;
729 }
730}
731
732enum CodingScheme ms_max_cs_ul(const struct GprsMs *ms)
733{
Pau Espin Pedrol201da4e2021-01-25 15:10:33 +0100734 enum CodingScheme cs;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100735 OSMO_ASSERT(ms->bts != NULL);
736
737 if (mcs_is_gprs(ms->current_cs_ul)) {
738 if (!bts_max_cs_ul(ms->bts)) {
739 return CS4;
740 }
741
742 return mcs_get_gprs_by_num(bts_max_cs_ul(ms->bts));
743 }
744
Pau Espin Pedrol201da4e2021-01-25 15:10:33 +0100745 cs = mcs_get_egprs_by_num(bts_max_mcs_ul(ms->bts));
746 if (ms_mode(ms) == EGPRS_GMSK && cs > MCS4)
747 cs = MCS4;
748 return cs;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100749}
750
751void ms_set_current_cs_dl(struct GprsMs *ms, enum CodingScheme scheme)
752{
753 ms->current_cs_dl = scheme;
754}
755
756enum CodingScheme ms_max_cs_dl(const struct GprsMs *ms)
757{
Pau Espin Pedrol201da4e2021-01-25 15:10:33 +0100758 enum CodingScheme cs;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100759 OSMO_ASSERT(ms->bts != NULL);
760
761 if (mcs_is_gprs(ms->current_cs_dl)) {
762 if (!bts_max_cs_dl(ms->bts)) {
763 return CS4;
764 }
765
766 return mcs_get_gprs_by_num(bts_max_cs_dl(ms->bts));
767 }
768
Pau Espin Pedrol201da4e2021-01-25 15:10:33 +0100769 cs = mcs_get_egprs_by_num(bts_max_mcs_dl(ms->bts));
770 if (ms_mode(ms) == EGPRS_GMSK && cs > MCS4)
771 cs = MCS4;
772 return cs;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100773}
774
775void ms_update_cs_ul(struct GprsMs *ms, const struct pcu_l1_meas *meas)
776{
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100777 enum CodingScheme max_cs_ul = ms_max_cs_ul(ms);
778
779 int old_link_qual;
780 int low;
781 int high;
782 enum CodingScheme new_cs_ul = ms->current_cs_ul;
783 uint8_t current_cs = mcs_chan_code(ms->current_cs_ul);
784
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100785 if (!max_cs_ul) {
786 LOGP(DRLCMACMEAS, LOGL_ERROR,
787 "max_cs_ul cannot be derived (current UL CS: %s)\n",
788 mcs_name(ms->current_cs_ul));
789 return;
790 }
791
792 if (!ms->current_cs_ul) {
793 LOGP(DRLCMACMEAS, LOGL_ERROR,
794 "Unable to update UL (M)CS because it's not set: %s\n",
795 mcs_name(ms->current_cs_ul));
796 return;
797 }
798
799 if (!meas->have_link_qual) {
800 LOGP(DRLCMACMEAS, LOGL_ERROR,
801 "Unable to update UL (M)CS %s because we don't have link quality measurements.\n",
802 mcs_name(ms->current_cs_ul));
803 return;
804 }
805
806 if (mcs_is_gprs(ms->current_cs_ul)) {
807 if (current_cs >= MAX_GPRS_CS)
808 current_cs = MAX_GPRS_CS - 1;
Pau Espin Pedrol54b159a2021-01-14 13:30:04 +0100809 low = the_pcu->vty.cs_lqual_ranges[current_cs].low;
810 high = the_pcu->vty.cs_lqual_ranges[current_cs].high;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100811 } else if (mcs_is_edge(ms->current_cs_ul)) {
812 if (current_cs >= MAX_EDGE_MCS)
813 current_cs = MAX_EDGE_MCS - 1;
Pau Espin Pedrol54b159a2021-01-14 13:30:04 +0100814 low = the_pcu->vty.mcs_lqual_ranges[current_cs].low;
815 high = the_pcu->vty.mcs_lqual_ranges[current_cs].high;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100816 } else {
817 LOGP(DRLCMACMEAS, LOGL_ERROR,
818 "Unable to update UL (M)CS because it's neither GPRS nor EDGE: %s\n",
819 mcs_name(ms->current_cs_ul));
820 return;
821 }
822
823 /* To avoid rapid changes of the coding scheme, we also take
824 * the old link quality value into account (if present). */
825 if (ms->l1_meas.have_link_qual)
826 old_link_qual = ms->l1_meas.link_qual;
827 else
828 old_link_qual = meas->link_qual;
829
830 if (meas->link_qual < low && old_link_qual < low)
831 mcs_dec_kind(&new_cs_ul, ms_mode(ms));
832 else if (meas->link_qual > high && old_link_qual > high &&
833 ms->current_cs_ul < max_cs_ul)
834 mcs_inc_kind(&new_cs_ul, ms_mode(ms));
835
836 if (ms->current_cs_ul != new_cs_ul) {
837 LOGPMS(ms, DRLCMACMEAS, LOGL_INFO,
838 "Link quality %ddB (old %ddB) left window [%d, %d], "
839 "modifying uplink CS level: %s -> %s\n",
840 meas->link_qual, old_link_qual,
841 low, high,
842 mcs_name(ms->current_cs_ul), mcs_name(new_cs_ul));
843
844 ms->current_cs_ul = new_cs_ul;
845 }
846}
847
848void ms_update_l1_meas(struct GprsMs *ms, const struct pcu_l1_meas *meas)
849{
850 unsigned i;
851
852 ms_update_cs_ul(ms, meas);
853
854 if (meas->have_rssi)
855 pcu_l1_meas_set_rssi(&ms->l1_meas, meas->rssi);
856 if (meas->have_bto)
857 pcu_l1_meas_set_bto(&ms->l1_meas, meas->bto);
858 if (meas->have_ber)
859 pcu_l1_meas_set_ber(&ms->l1_meas, meas->ber);
860 if (meas->have_link_qual)
861 pcu_l1_meas_set_link_qual(&ms->l1_meas, meas->link_qual);
862
863 if (meas->have_ms_rx_qual)
864 pcu_l1_meas_set_ms_rx_qual(&ms->l1_meas, meas->ms_rx_qual);
865 if (meas->have_ms_c_value)
866 pcu_l1_meas_set_ms_c_value(&ms->l1_meas, meas->ms_c_value);
867 if (meas->have_ms_sign_var)
868 pcu_l1_meas_set_ms_sign_var(&ms->l1_meas, meas->ms_sign_var);
869
870 if (meas->have_ms_i_level) {
871 for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
872 if (meas->ts[i].have_ms_i_level)
873 pcu_l1_meas_set_ms_i_level(&ms->l1_meas, i, meas->ts[i].ms_i_level);
874 else
875 ms->l1_meas.ts[i].have_ms_i_level = 0;
876 }
877 }
878}
879
Pau Espin Pedrolfc464932021-01-25 12:05:32 +0100880/* req_mcs_kind acts as a set filter, where EGPRS means any and GPRS is the most restrictive */
881enum CodingScheme ms_current_cs_dl(const struct GprsMs *ms, enum mcs_kind req_mcs_kind)
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100882{
Pau Espin Pedrolfc464932021-01-25 12:05:32 +0100883 enum CodingScheme orig_cs = ms->current_cs_dl;
884 struct gprs_rlcmac_bts *bts = ms->bts;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100885 size_t unencoded_octets;
Pau Espin Pedrolfc464932021-01-25 12:05:32 +0100886 enum CodingScheme cs;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100887
Pau Espin Pedrolfc464932021-01-25 12:05:32 +0100888 /* It could be that a TBF requests a GPRS CS despite the MS currently
889 being upgraded to EGPRS (hence reporting MCS). That could happen
890 because the TBF was created early in the process where we didn't have
891 yet enough information about the MS, and only AFTER it was created we
892 upgraded the MS to be EGPRS capable.
893 As a result, when the MS is queried for the target CS here, we could be
894 returning an MCS despite the current TBF being established as GPRS,
895 but we rather stick to the TBF type we assigned to the MS rather than
896 magically sending EGPRS data blocks to a GPRS TBF.
897 It could also be that the caller requests specific MCS kind
898 explicitly too due to scheduling restrictions (GPRS+EGPRS multiplexing). */
899 if (req_mcs_kind == EGPRS_GMSK && mcs_is_edge(orig_cs) && orig_cs > MCS4) {
900 cs = bts_cs_dl_is_supported(bts, MCS4) ? MCS4 :
901 bts_cs_dl_is_supported(bts, MCS3) ? MCS3 :
902 bts_cs_dl_is_supported(bts, MCS2) ? MCS2 :
903 MCS1;
904 } else if (req_mcs_kind == GPRS && mcs_is_edge(orig_cs)) { /* GPRS */
905 int i;
906 cs = orig_cs > MCS4 ? MCS4 : orig_cs;
907 cs -= (MCS1 - CS1); /* MCSx -> CSx */
908 /* Find suitable CS starting from equivalent MCS which is supported by BTS: */
909 for (i = mcs_chan_code(cs); !bts_cs_dl_is_supported(bts, CS1 + i); i--);
910 OSMO_ASSERT(i >= 0 && i <= 3); /* CS1 is always supported */
911 cs = CS1 + i;
912 } else {
913 cs = orig_cs;
914 }
915
916 if (orig_cs != cs)
917 LOGPMS(ms, DRLCMACDL, LOGL_INFO, "MS (mode=%s) suggests transmitting "
918 "DL %s, downgrade to %s in order to match TBF & scheduler requirements\n",
919 mode_name(ms_mode(ms)), mcs_name(orig_cs), mcs_name(cs));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100920
921 unencoded_octets = llc_queue_octets(&ms->llc_queue);
922
923 /* If the DL TBF is active, add number of unencoded chunk octets */
924 if (ms->dl_tbf)
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200925 unencoded_octets += llc_chunk_size(tbf_llc(dl_tbf_as_tbf(ms->dl_tbf)));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100926
927 /* There are many unencoded octets, don't reduce */
Pau Espin Pedrolad79b852021-01-14 13:20:55 +0100928 if (unencoded_octets >= the_pcu->vty.cs_downgrade_threshold)
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100929 return cs;
930
931 /* RF conditions are good, don't reduce */
Pau Espin Pedrole8dcf642021-01-14 13:17:01 +0100932 if (ms->nack_rate_dl < the_pcu->vty.cs_adj_lower_limit)
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100933 return cs;
934
935 /* The throughput would probably be better if the CS level was reduced */
936 mcs_dec_kind(&cs, ms_mode(ms));
937
938 /* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
939 if (cs == CS2)
940 mcs_dec_kind(&cs, ms_mode(ms));
941
942 return cs;
943}
944
Pau Espin Pedrol9935d0d2022-12-13 18:29:25 +0100945struct gprs_rlcmac_pdch *ms_first_common_ts(const struct GprsMs *ms)
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100946{
Pau Espin Pedrol345d9ad2022-12-12 19:22:44 +0100947 return ms->first_common_ts;
948}
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100949
Pau Espin Pedrol9935d0d2022-12-13 18:29:25 +0100950void ms_set_first_common_ts(struct GprsMs *ms, struct gprs_rlcmac_pdch *pdch)
Pau Espin Pedrol345d9ad2022-12-12 19:22:44 +0100951{
Pau Espin Pedrol9935d0d2022-12-13 18:29:25 +0100952 OSMO_ASSERT(pdch);
953 ms->first_common_ts = pdch;
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100954}
955
956uint8_t ms_dl_slots(const struct GprsMs *ms)
957{
958 uint8_t slots = 0;
959
960 if (ms->dl_tbf)
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200961 slots |= tbf_dl_slots(dl_tbf_as_tbf(ms->dl_tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100962
963 if (ms->ul_tbf)
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200964 slots |= tbf_dl_slots(ul_tbf_as_tbf(ms->ul_tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100965
966 return slots;
967}
968
969uint8_t ms_ul_slots(const struct GprsMs *ms)
970{
971 uint8_t slots = 0;
972
973 if (ms->dl_tbf)
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200974 slots |= tbf_ul_slots(dl_tbf_as_tbf(ms->dl_tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100975
976 if (ms->ul_tbf)
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200977 slots |= tbf_ul_slots(ul_tbf_as_tbf(ms->ul_tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100978
979 return slots;
980}
981
982uint8_t ms_current_pacch_slots(const struct GprsMs *ms)
983{
984 uint8_t slots = 0;
985
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200986 bool is_dl_active = ms->dl_tbf && tbf_is_tfi_assigned(dl_tbf_as_tbf(ms->dl_tbf));
987 bool is_ul_active = ms->ul_tbf && tbf_is_tfi_assigned(ul_tbf_as_tbf(ms->ul_tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100988
989 if (!is_dl_active && !is_ul_active)
990 return 0;
991
992 /* see TS 44.060, 8.1.1.2.2 */
993 if (is_dl_active && !is_ul_active)
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200994 slots = tbf_dl_slots(dl_tbf_as_tbf(ms->dl_tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100995 else if (!is_dl_active && is_ul_active)
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200996 slots = tbf_ul_slots(ul_tbf_as_tbf(ms->ul_tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +0100997 else
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +0200998 slots = tbf_ul_slots(ul_tbf_as_tbf(ms->ul_tbf)) &
999 tbf_dl_slots(dl_tbf_as_tbf(ms->dl_tbf));
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +01001000
1001 /* Assume a multislot class 1 device */
1002 /* TODO: For class 2 devices, this could be removed */
1003 slots = pcu_lsb(slots);
1004
1005 return slots;
1006}
1007
1008void ms_set_reserved_slots(struct GprsMs *ms, struct gprs_rlcmac_trx *trx,
1009 uint8_t ul_slots, uint8_t dl_slots)
1010{
1011 if (ms->current_trx) {
1012 bts_trx_unreserve_slots(ms->current_trx, GPRS_RLCMAC_DL_TBF,
1013 ms->reserved_dl_slots);
1014 bts_trx_unreserve_slots(ms->current_trx, GPRS_RLCMAC_UL_TBF,
1015 ms->reserved_ul_slots);
1016 ms->reserved_dl_slots = 0;
1017 ms->reserved_ul_slots = 0;
1018 }
1019 ms->current_trx = trx;
1020 if (trx) {
1021 ms->reserved_dl_slots = dl_slots;
1022 ms->reserved_ul_slots = ul_slots;
1023 bts_trx_reserve_slots(ms->current_trx, GPRS_RLCMAC_DL_TBF,
1024 ms->reserved_dl_slots);
1025 bts_trx_reserve_slots(ms->current_trx, GPRS_RLCMAC_UL_TBF,
1026 ms->reserved_ul_slots);
1027 }
1028}
1029
1030struct gprs_rlcmac_tbf *ms_tbf(const struct GprsMs *ms, enum gprs_rlcmac_tbf_direction dir)
1031{
1032 switch (dir) {
Pau Espin Pedrol1e16e1d2022-10-27 15:40:20 +02001033 case GPRS_RLCMAC_DL_TBF: return dl_tbf_as_tbf(ms->dl_tbf);
1034 case GPRS_RLCMAC_UL_TBF: return ul_tbf_as_tbf(ms->ul_tbf);
Pau Espin Pedrolda971ee2020-12-16 15:59:45 +01001035 }
1036
1037 return NULL;
1038}
Pau Espin Pedrolc0a250d2021-01-21 18:46:13 +01001039
Pau Espin Pedrol3547d642022-10-21 15:00:08 +02001040const char *ms_name(const struct GprsMs *ms)
1041{
1042 static char _ms_name_buf[128];
1043 return ms_name_buf(ms, _ms_name_buf, sizeof(_ms_name_buf));
1044}
1045
1046char *ms_name_buf(const struct GprsMs *ms, char *buf, unsigned int buf_size)
1047{
Pau Espin Pedrol94f82582022-11-03 14:16:17 +01001048 struct osmo_strbuf sb = { .buf = buf, .len = buf_size };
1049 uint32_t tlli = ms_tlli(ms);
1050
1051 OSMO_STRBUF_PRINTF(sb, "MS(");
1052 if (ms_imsi_is_valid(ms))
1053 OSMO_STRBUF_PRINTF(sb, "IMSI-%s:", ms_imsi(ms));
1054 if (tlli != GSM_RESERVED_TMSI)
1055 OSMO_STRBUF_PRINTF(sb, "TLLI-0x%08x:", tlli);
1056 OSMO_STRBUF_PRINTF(sb, "TA-%" PRIu8 ":MSCLS-%" PRIu8 "-%" PRIu8,
1057 ms_ta(ms), ms_ms_class(ms), ms_egprs_ms_class(ms));
1058 if (ms->ul_tbf)
1059 OSMO_STRBUF_PRINTF(sb, ":UL");
1060 if (ms->dl_tbf)
1061 OSMO_STRBUF_PRINTF(sb, ":DL");
1062
1063 OSMO_STRBUF_PRINTF(sb, ")");
Pau Espin Pedrol3547d642022-10-21 15:00:08 +02001064 return buf;
1065}
1066
Pau Espin Pedrolc0a250d2021-01-21 18:46:13 +01001067int ms_nacc_start(struct GprsMs *ms, Packet_Cell_Change_Notification_t *notif)
1068{
1069 if (!ms->nacc)
1070 ms->nacc = nacc_fsm_alloc(ms);
1071 if (!ms->nacc)
1072 return -EINVAL;
1073 return osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_RX_CELL_CHG_NOTIFICATION, notif);
1074}
1075
1076bool ms_nacc_rts(const struct GprsMs *ms)
1077{
1078 if (!ms->nacc)
1079 return false;
1080 if (ms->nacc->fi->state == NACC_ST_TX_NEIGHBOUR_DATA ||
1081 ms->nacc->fi->state == NACC_ST_TX_CELL_CHG_CONTINUE)
1082 return true;
1083 return false;
1084}
1085
Pau Espin Pedrol5ba3ef92022-12-12 18:02:25 +01001086struct msgb *ms_nacc_create_rlcmac_msg(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf,
1087 const struct gprs_rlcmac_pdch *pdch, uint32_t fn)
Pau Espin Pedrolc0a250d2021-01-21 18:46:13 +01001088{
1089 int rc;
1090 struct nacc_ev_create_rlcmac_msg_ctx data_ctx;
1091
Pau Espin Pedrol952cb3d2021-02-01 14:52:48 +01001092 data_ctx = (struct nacc_ev_create_rlcmac_msg_ctx) {
1093 .tbf = tbf,
Pau Espin Pedrol5ba3ef92022-12-12 18:02:25 +01001094 .pdch = pdch,
Pau Espin Pedrol952cb3d2021-02-01 14:52:48 +01001095 .fn = fn,
Pau Espin Pedrol952cb3d2021-02-01 14:52:48 +01001096 .msg = NULL,
1097 };
Pau Espin Pedrolc0a250d2021-01-21 18:46:13 +01001098
1099 rc = osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_CREATE_RLCMAC_MSG, &data_ctx);
1100 if (rc != 0 || !data_ctx.msg)
1101 return NULL;
1102 return data_ctx.msg;
1103}
Pau Espin Pedrol14beef62022-10-26 19:44:07 +02001104
1105static void ms_start_llc_timer(struct GprsMs *ms)
1106{
1107 if (the_pcu->vty.llc_idle_ack_csec > 0) {
1108 struct timespec tv;
1109 csecs_to_timespec(the_pcu->vty.llc_idle_ack_csec, &tv);
1110 osmo_timer_schedule(&ms->llc_timer, tv.tv_sec, tv.tv_nsec / 1000);
1111 }
1112}
1113
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +02001114/* Can we get to send a DL TBF ass to the MS? */
1115static bool ms_is_reachable_for_dl_ass(const struct GprsMs *ms)
1116{
1117 struct gprs_rlcmac_ul_tbf *ul_tbf = ms_ul_tbf(ms);
1118
1119 /* This function assumes it is called when no DL TBF is present */
1120 OSMO_ASSERT(!ms_dl_tbf(ms));
1121
1122 /* 3GPP TS 44.060 sec 7.1.3.1 Initiation of the Packet resource request procedure:
1123 * "Furthermore, the mobile station shall not respond to PACKET DOWNLINK ASSIGNMENT
1124 * or MULTIPLE TBF DOWNLINK ASSIGNMENT messages before contention resolution is
1125 * completed on the mobile station side." */
1126 /* The possible uplink TBF is used to trigger downlink assignment:
1127 * - If there is no uplink TBF the MS is potentially in packet idle mode
1128 * and hence assignment will be done over CCCH (PCH)
1129 * - If there's an uplink TBF but it is finished (waiting for last PKT
1130 * CTRL ACK after sending last Pkt UL ACK/NACK with FINAL_ACK=1, then we
1131 * have no ways to contact the MS right now. Assignment will be delayed
1132 * until PKT CTRL ACK is received and the TBF is released at the MS side
1133 * (then assignment goes through PCH).
1134 */
1135 if (!ul_tbf)
1136 return true;
1137 if (ul_tbf_contention_resolution_done(ul_tbf) &&
1138 !tbf_ul_ack_waiting_cnf_final_ack(ul_tbf))
1139 return true;
1140
1141 return false;
1142
1143}
1144
Pau Espin Pedrol94386132022-10-28 19:50:09 +02001145/* Alloc a UL TBF to be assigned over PACCH. Called when an MS requests to
1146 * create a new UL TBF during the end of life of a previous UL TBF (or an SBA).
1147 * In summary, this TBF is allocated as a consequence of receiving a "Pkt
1148 * Resource Req" or "Pkt Ctrl Ack" from the MS.
1149 * See TS 44.060 9.3.2.4.2 "Non-extended uplink TBF mode".
1150 */
1151struct gprs_rlcmac_ul_tbf *ms_new_ul_tbf_assigned_pacch(struct GprsMs *ms, int8_t use_trx)
1152{
1153 const bool single_slot = false;
1154 struct gprs_rlcmac_ul_tbf *ul_tbf;
1155
Pau Espin Pedrolbda7bb72022-10-31 14:33:09 +01001156 ul_tbf = ul_tbf_alloc(ms->bts, ms, use_trx, single_slot);
Pau Espin Pedrol94386132022-10-28 19:50:09 +02001157 if (!ul_tbf) {
1158 LOGPMS(ms, DTBF, LOGL_NOTICE, "No PDCH resource\n");
1159 /* Caller will most probably send a Imm Ass Reject after return */
1160 return NULL;
1161 }
1162 osmo_fsm_inst_dispatch(tbf_state_fi(ul_tbf_as_tbf(ul_tbf)), TBF_EV_ASSIGN_ADD_PACCH, NULL);
1163 /* Contention resolution is considered to be done since TLLI is known in MS */
1164 return ul_tbf;
1165}
1166
1167/* Alloc a UL TBF to be assigned over AGCH. Used by request of a "One phase
1168 * packet access", where MS requested only 1 PDCH TS (TS 44.018 Table 9.1.8.1). */
1169struct gprs_rlcmac_ul_tbf *ms_new_ul_tbf_assigned_agch(struct GprsMs *ms)
1170{
1171 const int8_t trx_no = -1;
1172 const bool single_slot = true;
1173 struct gprs_rlcmac_ul_tbf *ul_tbf;
1174
Pau Espin Pedrolbda7bb72022-10-31 14:33:09 +01001175 ul_tbf = ul_tbf_alloc(ms->bts, ms, trx_no, single_slot);
Pau Espin Pedrol94386132022-10-28 19:50:09 +02001176 if (!ul_tbf) {
1177 LOGP(DTBF, LOGL_NOTICE, "No PDCH resource for Uplink TBF\n");
1178 /* Caller will most probably send a Imm Ass Reject after return */
1179 return NULL;
1180 }
1181 osmo_fsm_inst_dispatch(tbf_state_fi(ul_tbf_as_tbf(ul_tbf)), TBF_EV_ASSIGN_ADD_CCCH, NULL);
1182 return ul_tbf;
1183}
1184
Pau Espin Pedrola621d592022-12-13 17:35:04 +01001185/* Create a temporary dummy TBF to Tx a ImmAssReject if allocating a new one during
1186 * packet resource Request failed. This is similar as ul_tbf_alloc() but without
1187 * calling tbf->setup() (in charge of TFI/USF allocation), and reusing resources
1188 * from Packet Resource Request we received. See TS 44.060 sec 7.1.3.2.1 */
1189struct gprs_rlcmac_ul_tbf *ms_new_ul_tbf_rejected_pacch(struct GprsMs *ms, struct gprs_rlcmac_pdch *pdch)
1190{
1191 struct gprs_rlcmac_ul_tbf *ul_tbf;
1192 ul_tbf = ul_tbf_alloc_rejected(ms->bts, ms, pdch);
1193 if (!ul_tbf)
1194 return NULL;
1195 osmo_fsm_inst_dispatch(tbf_state_fi(ul_tbf_as_tbf(ul_tbf)), TBF_EV_ASSIGN_ADD_PACCH, NULL);
1196 osmo_fsm_inst_dispatch(tbf_ul_ass_fi(ul_tbf_as_tbf(ul_tbf)), TBF_UL_ASS_EV_SCHED_ASS_REJ, NULL);
1197
1198 return ul_tbf;
1199}
1200
Pau Espin Pedrol091642a2022-10-28 18:01:31 +02001201/* A new DL-TBF is allocated and assigned through PACCH using "tbf".
1202 * "tbf" may be either a UL-TBF or a DL-TBF.
1203 * Note: This should be called only when MS is reachable, see ms_is_reachable_for_dl_ass().
1204 */
1205int ms_new_dl_tbf_assigned_on_pacch(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +02001206{
Pau Espin Pedrol091642a2022-10-28 18:01:31 +02001207 OSMO_ASSERT(tbf);
1208 const int8_t trx_no = tbf_get_trx(tbf)->trx_no;
1209 const bool single_slot = false;
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +02001210 struct gprs_rlcmac_dl_tbf *dl_tbf;
1211
Pau Espin Pedrol091642a2022-10-28 18:01:31 +02001212 dl_tbf = dl_tbf_alloc(ms->bts, ms, trx_no, single_slot);
1213 if (!dl_tbf) {
1214 LOGPMS(ms, DTBF, LOGL_NOTICE, "No PDCH resource\n");
1215 return -EBUSY;
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +02001216 }
1217
Pau Espin Pedrol091642a2022-10-28 18:01:31 +02001218 LOGPTBFDL(dl_tbf, LOGL_DEBUG, "[DOWNLINK] START (PACCH)\n");
1219 dl_tbf_trigger_ass_on_pacch(dl_tbf, tbf);
1220 return 0;
1221}
1222
1223/* A new DL-TBF is allocated and assigned through PCH.
1224 * Note: This should be called only when MS is reachable, see ms_is_reachable_for_dl_ass().
1225 */
1226int ms_new_dl_tbf_assigned_on_pch(struct GprsMs *ms)
1227{
1228 const int8_t trx_no = -1;
1229 const bool single_slot = true;
1230 struct gprs_rlcmac_dl_tbf *dl_tbf;
1231
1232 dl_tbf = dl_tbf_alloc(ms->bts, ms, trx_no, single_slot);
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +02001233 if (!dl_tbf) {
1234 LOGPMS(ms, DTBF, LOGL_NOTICE, "No PDCH resource\n");
1235 return -EBUSY;
1236 }
1237
Pau Espin Pedrol091642a2022-10-28 18:01:31 +02001238 LOGPTBFDL(dl_tbf, LOGL_DEBUG, "[DOWNLINK] START (PCH)\n");
1239 dl_tbf_trigger_ass_on_pch(dl_tbf);
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +02001240 return 0;
1241}
1242
Pau Espin Pedrol14beef62022-10-26 19:44:07 +02001243int ms_append_llc_dl_data(struct GprsMs *ms, uint16_t pdu_delay_csec, const uint8_t *data, uint16_t len)
1244{
1245 struct timespec expire_time;
1246 struct gprs_rlcmac_dl_tbf *dl_tbf;
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +02001247 int rc = 0;
Pau Espin Pedrol14beef62022-10-26 19:44:07 +02001248
1249 LOGPMS(ms, DTBFDL, LOGL_DEBUG, "appending %u bytes to DL LLC queue\n", len);
1250
1251 struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue");
1252 if (!llc_msg)
1253 return -ENOMEM;
1254
1255 llc_queue_calc_pdu_lifetime(ms->bts, pdu_delay_csec, &expire_time);
1256 memcpy(msgb_put(llc_msg, len), data, len);
1257 llc_queue_enqueue(ms_llc_queue(ms), llc_msg, &expire_time);
1258 ms_start_llc_timer(ms);
1259
1260 dl_tbf = ms_dl_tbf(ms);
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +02001261 if (dl_tbf) {
1262 if (tbf_state(dl_tbf_as_tbf_const(dl_tbf)) == TBF_ST_WAIT_RELEASE) {
1263 LOGPTBFDL(dl_tbf, LOGL_DEBUG, "in WAIT RELEASE state (T3193), so reuse TBF\n");
Pau Espin Pedrol091642a2022-10-28 18:01:31 +02001264 rc = ms_new_dl_tbf_assigned_on_pacch(ms, dl_tbf_as_tbf(dl_tbf));
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +02001265 }
1266 } else {
1267 /* Check if we can create a DL TBF to start sending the enqueued
1268 * data. Otherwise it will be triggered later when it is reachable
1269 * again. */
Pau Espin Pedrol091642a2022-10-28 18:01:31 +02001270 if (ms_is_reachable_for_dl_ass(ms)) {
1271 if (ms_ul_tbf(ms))
1272 rc = ms_new_dl_tbf_assigned_on_pacch(ms, ul_tbf_as_tbf(ms_ul_tbf(ms)));
1273 else
1274 rc = ms_new_dl_tbf_assigned_on_pch(ms);
1275 }
Pau Espin Pedrol14beef62022-10-26 19:44:07 +02001276 }
Pau Espin Pedrol22b26d82022-10-26 15:44:14 +02001277 return rc;
Pau Espin Pedrol14beef62022-10-26 19:44:07 +02001278}