blob: ab0b643095cd76d7022e71f5a303b9dee720d6a2 [file] [log] [blame]
Oliver Smith10632132023-05-12 12:14:22 +02001/* 3GPP TS 122.002 Bearer Services */
2/*
3 * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * Author: Oliver Smith
7 *
8 * SPDX-License-Identifier: AGPL-3.0+
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23#include <errno.h>
24
25#include <osmocom/msc/csd_bs.h>
26#include <osmocom/msc/debug.h>
27
28/* csd_bs related below */
29
30struct csd_bs_map {
31 /* BS number (20, 21, ...) */
32 unsigned int num;
33 /* Access Structure (1: asynchronous, 0: synchronous) */
34 bool async;
35 /* QoS Attribute (1: transparent, 0: non-transparent) */
36 bool transp;
37 /* Rate Adaption (V110, V120 etc.) */
38 enum gsm48_bcap_ra ra;
39 /* Fixed Network User Rate */
40 unsigned int rate;
41};
42
43static const struct csd_bs_map bs_map[] = {
44 /* 3.1.1.1.2 */
45 [CSD_BS_21_T_V110_0k3] = {
46 .num = 21,
47 .async = true,
48 .transp = true,
49 .ra = GSM48_BCAP_RA_V110_X30,
50 .rate = 300,
51 },
52 [CSD_BS_22_T_V110_1k2] = {
53 .num = 22,
54 .async = true,
55 .transp = true,
56 .ra = GSM48_BCAP_RA_V110_X30,
57 .rate = 1200,
58 },
59 [CSD_BS_24_T_V110_2k4] = {
60 .num = 24,
61 .async = true,
62 .transp = true,
63 .ra = GSM48_BCAP_RA_V110_X30,
64 .rate = 2400,
65 },
66 [CSD_BS_25_T_V110_4k8] = {
67 .num = 25,
68 .async = true,
69 .transp = true,
70 .ra = GSM48_BCAP_RA_V110_X30,
71 .rate = 4800,
72 },
73 [CSD_BS_26_T_V110_9k6] = {
74 .num = 26,
75 .async = true,
76 .transp = true,
77 .ra = GSM48_BCAP_RA_V110_X30,
78 .rate = 9600,
79 },
80
81 /* 3.1.1.2.2 */
82 [CSD_BS_21_NT_V110_0k3] = {
83 .num = 21,
84 .async = true,
85 .transp = false,
86 .ra = GSM48_BCAP_RA_V110_X30,
87 .rate = 300,
88 },
89 [CSD_BS_22_NT_V110_1k2] = {
90 .num = 22,
91 .async = true,
92 .transp = false,
93 .ra = GSM48_BCAP_RA_V110_X30,
94 .rate = 1200,
95 },
96 [CSD_BS_24_NT_V110_2k4] = {
97 .num = 24,
98 .async = true,
99 .transp = false,
100 .ra = GSM48_BCAP_RA_V110_X30,
101 .rate = 2400,
102 },
103 [CSD_BS_25_NT_V110_4k8] = {
104 .num = 25,
105 .async = true,
106 .transp = false,
107 .ra = GSM48_BCAP_RA_V110_X30,
108 .rate = 4800,
109 },
110 [CSD_BS_26_NT_V110_9k6] = {
111 .num = 26,
112 .async = true,
113 .transp = false,
114 .ra = GSM48_BCAP_RA_V110_X30,
115 .rate = 9600,
116 },
117
118 /* 3.1.2.1.2 */
119 [CSD_BS_31_T_V110_1k2] = {
120 .num = 31,
121 .async = false,
122 .transp = true,
123 .ra = GSM48_BCAP_RA_V110_X30,
124 .rate = 1200,
125 },
126 [CSD_BS_32_T_V110_2k4] = {
127 .num = 32,
128 .async = false,
129 .transp = true,
130 .ra = GSM48_BCAP_RA_V110_X30,
131 .rate = 2400,
132 },
133 [CSD_BS_33_T_V110_4k8] = {
134 .num = 33,
135 .async = false,
136 .transp = true,
137 .ra = GSM48_BCAP_RA_V110_X30,
138 .rate = 4800,
139 },
140 [CSD_BS_34_T_V110_9k6] = {
141 .num = 34,
142 .async = false,
143 .transp = true,
144 .ra = GSM48_BCAP_RA_V110_X30,
145 .rate = 9600,
146 },
147};
148
149osmo_static_assert(ARRAY_SIZE(bs_map) == CSD_BS_MAX, _invalid_size_bs_map);
150
151bool csd_bs_is_transp(enum csd_bs bs)
152{
153 return bs_map[bs].transp;
154}
155
156/* Short single-line representation, convenient for logging.
157 * Like "BS25NT" */
158int csd_bs_to_str_buf(char *buf, size_t buflen, enum csd_bs bs)
159{
160 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
161 const struct csd_bs_map *map = &bs_map[bs];
162
163 OSMO_STRBUF_PRINTF(sb, "BS%u%s",
164 map->num,
165 map->transp ? "T" : "NT");
166
167 if (map->ra != GSM48_BCAP_RA_V110_X30)
168 OSMO_STRBUF_PRINTF(sb, "-RA=%d", map->ra);
169
170 return sb.chars_needed;
171}
172
173char *csd_bs_to_str_c(void *ctx, enum csd_bs bs)
174{
175 OSMO_NAME_C_IMPL(ctx, 32, "csd_bs_to_str_c-ERROR", csd_bs_to_str_buf, bs)
176}
177
178const char *csd_bs_to_str(enum csd_bs bs)
179{
180 return csd_bs_to_str_c(OTC_SELECT, bs);
181}
182
Oliver Smith80654ed2023-07-06 10:59:57 +0200183static int csd_bs_to_gsm0808_data_rate_transp(enum csd_bs bs, uint8_t *ch_rate_type)
Oliver Smith10632132023-05-12 12:14:22 +0200184{
185 switch (bs_map[bs].rate) {
Oliver Smith80654ed2023-07-06 10:59:57 +0200186 case 300:
187 *ch_rate_type = GSM0808_DATA_FULL_PREF;
188 return GSM0808_DATA_RATE_TRANSP_600;
Oliver Smith10632132023-05-12 12:14:22 +0200189 case 1200:
Oliver Smith80654ed2023-07-06 10:59:57 +0200190 *ch_rate_type = GSM0808_DATA_FULL_PREF;
Oliver Smith10632132023-05-12 12:14:22 +0200191 return GSM0808_DATA_RATE_TRANSP_1k2;
192 case 2400:
Oliver Smith80654ed2023-07-06 10:59:57 +0200193 *ch_rate_type = GSM0808_DATA_FULL_PREF;
Oliver Smith10632132023-05-12 12:14:22 +0200194 return GSM0808_DATA_RATE_TRANSP_2k4;
195 case 4800:
Oliver Smith80654ed2023-07-06 10:59:57 +0200196 *ch_rate_type = GSM0808_DATA_FULL_PREF;
Oliver Smith10632132023-05-12 12:14:22 +0200197 return GSM0808_DATA_RATE_TRANSP_4k8;
198 case 9600:
Oliver Smith80654ed2023-07-06 10:59:57 +0200199 *ch_rate_type = GSM0808_DATA_FULL_BM;
Oliver Smith10632132023-05-12 12:14:22 +0200200 return GSM0808_DATA_RATE_TRANSP_9k6;
201 }
202 return -EINVAL;
203}
204
Oliver Smith80654ed2023-07-06 10:59:57 +0200205static int csd_bs_to_gsm0808_data_rate_non_transp(enum csd_bs bs, uint8_t *ch_rate_type)
Oliver Smith10632132023-05-12 12:14:22 +0200206{
207 uint16_t rate = bs_map[bs].rate;
208
Oliver Smith80654ed2023-07-06 10:59:57 +0200209 if (rate < 6000) {
210 *ch_rate_type = GSM0808_DATA_FULL_PREF;
Oliver Smith10632132023-05-12 12:14:22 +0200211 return GSM0808_DATA_RATE_NON_TRANSP_6k0;
Oliver Smith80654ed2023-07-06 10:59:57 +0200212 }
213 if (rate < 12000) {
214 *ch_rate_type = GSM0808_DATA_FULL_BM;
Oliver Smith10632132023-05-12 12:14:22 +0200215 return GSM0808_DATA_RATE_NON_TRANSP_12k0;
Oliver Smith80654ed2023-07-06 10:59:57 +0200216 }
Oliver Smith10632132023-05-12 12:14:22 +0200217
218 return -EINVAL;
219}
220
221static int csd_bs_to_gsm0808_data_rate_non_transp_allowed(enum csd_bs bs)
222{
223 uint16_t rate = bs_map[bs].rate;
224
225 if (rate < 6000)
226 return GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_6k0;
227 if (rate < 12000)
228 return GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_12k0;
229
230 return -EINVAL;
231}
232
233enum csd_bs csd_bs_from_bearer_cap(const struct gsm_mncc_bearer_cap *cap, bool transp)
234{
235 enum gsm48_bcap_ra ra = cap->data.rate_adaption;
236 enum gsm48_bcap_user_rate rate = cap->data.user_rate;
237 bool async = cap->data.async;
238
Manawyrm29842352023-10-15 14:37:22 +0200239 /* 3.1kHz CSD calls won't have the rate adaptation field set
240 but do require rate adaptation. */
241 if (cap->data.interm_rate && !ra)
242 ra = GSM48_BCAP_RA_V110_X30;
243
Oliver Smith10632132023-05-12 12:14:22 +0200244 if (ra == GSM48_BCAP_RA_V110_X30 && async && transp) {
245 switch (rate) {
246 case GSM48_BCAP_UR_300:
247 return CSD_BS_21_T_V110_0k3;
248 case GSM48_BCAP_UR_1200:
249 return CSD_BS_22_T_V110_1k2;
250 case GSM48_BCAP_UR_2400:
251 return CSD_BS_24_T_V110_2k4;
252 case GSM48_BCAP_UR_4800:
253 return CSD_BS_25_T_V110_4k8;
254 case GSM48_BCAP_UR_9600:
255 return CSD_BS_26_T_V110_9k6;
256 default:
257 return CSD_BS_NONE;
258 }
259 }
260
261 if (ra == GSM48_BCAP_RA_V110_X30 && async && !transp) {
262 switch (rate) {
263 case GSM48_BCAP_UR_300:
264 return CSD_BS_21_NT_V110_0k3;
265 case GSM48_BCAP_UR_1200:
266 return CSD_BS_22_NT_V110_1k2;
267 case GSM48_BCAP_UR_2400:
268 return CSD_BS_24_NT_V110_2k4;
269 case GSM48_BCAP_UR_4800:
270 return CSD_BS_25_NT_V110_4k8;
271 case GSM48_BCAP_UR_9600:
272 return CSD_BS_26_NT_V110_9k6;
273 default:
274 return CSD_BS_NONE;
275 }
276 }
277
278 if (ra == GSM48_BCAP_RA_V110_X30 && !async && transp) {
279 switch (rate) {
280 case GSM48_BCAP_UR_1200:
281 return CSD_BS_31_T_V110_1k2;
282 case GSM48_BCAP_UR_2400:
283 return CSD_BS_32_T_V110_2k4;
284 case GSM48_BCAP_UR_4800:
285 return CSD_BS_33_T_V110_4k8;
286 case GSM48_BCAP_UR_9600:
287 return CSD_BS_34_T_V110_9k6;
288 default:
289 return CSD_BS_NONE;
290 }
291 }
292
293 return CSD_BS_NONE;
294}
295
296/* csd_bs_list related below */
297
298int csd_bs_list_to_str_buf(char *buf, size_t buflen, const struct csd_bs_list *list)
299{
300 struct osmo_strbuf sb = { .buf = buf, .len = buflen };
301 int i;
302
303 if (!list->count)
304 OSMO_STRBUF_PRINTF(sb, "(no-bearer-services)");
305
306 for (i = 0; i < list->count; i++) {
307 if (i)
308 OSMO_STRBUF_PRINTF(sb, ",");
309
310 OSMO_STRBUF_APPEND(sb, csd_bs_to_str_buf, list->bs[i]);
311 }
312 return sb.chars_needed;
313}
314
315char *csd_bs_list_to_str_c(void *ctx, const struct csd_bs_list *list)
316{
317 OSMO_NAME_C_IMPL(ctx, 128, "csd_bs_list_to_str_c-ERROR", csd_bs_list_to_str_buf, list)
318}
319
320const char *csd_bs_list_to_str(const struct csd_bs_list *list)
321{
322 return csd_bs_list_to_str_c(OTC_SELECT, list);
323}
324
325bool csd_bs_list_has_bs(const struct csd_bs_list *list, enum csd_bs bs)
326{
327 int i;
328
329 for (i = 0; i < list->count; i++) {
330 if (list->bs[i] == bs)
331 return true;
332 }
333
334 return false;
335}
336
337void csd_bs_list_add_bs(struct csd_bs_list *list, enum csd_bs bs)
338{
339 int i;
340
341 if (!bs)
342 return;
343
344 for (i = 0; i < list->count; i++) {
345 if (list->bs[i] == bs)
346 return;
347 }
348
349 list->bs[i] = bs;
350 list->count++;
351}
352
353void csd_bs_list_remove(struct csd_bs_list *list, enum csd_bs bs)
354{
355 int i;
356 bool found = false;
357
358 for (i = 0; i < list->count; i++) {
Oliver Smithfa006b82023-07-06 13:40:15 +0200359 if (list->bs[i] == bs)
Oliver Smith10632132023-05-12 12:14:22 +0200360 found = true;
Oliver Smithfa006b82023-07-06 13:40:15 +0200361 if (found && i + 1 < list->count)
362 list->bs[i] = list->bs[i + 1];
Oliver Smith10632132023-05-12 12:14:22 +0200363 }
Oliver Smithfa006b82023-07-06 13:40:15 +0200364
365 if (found)
366 list->count--;
Oliver Smith10632132023-05-12 12:14:22 +0200367}
368
369void csd_bs_list_intersection(struct csd_bs_list *dest, const struct csd_bs_list *other)
370{
371 int i;
372
373 for (i = 0; i < dest->count; i++) {
374 if (csd_bs_list_has_bs(other, dest->bs[i]))
375 continue;
376 csd_bs_list_remove(dest, dest->bs[i]);
377 i--;
378 }
379}
380
381int csd_bs_list_to_gsm0808_channel_type(struct gsm0808_channel_type *ct, const struct csd_bs_list *list)
382{
383 int i;
384 int rc;
385
386 *ct = (struct gsm0808_channel_type){
387 .ch_indctr = GSM0808_CHAN_DATA,
388 };
389
Oliver Smith6de3d6c2023-08-22 13:08:24 +0200390 if (!list->count)
391 return -EINVAL;
Oliver Smith10632132023-05-12 12:14:22 +0200392
393 if (csd_bs_is_transp(list->bs[0])) {
394 ct->data_transparent = true;
Oliver Smith80654ed2023-07-06 10:59:57 +0200395 rc = csd_bs_to_gsm0808_data_rate_transp(list->bs[0], &ct->ch_rate_type);
Oliver Smith10632132023-05-12 12:14:22 +0200396 } else {
Oliver Smith80654ed2023-07-06 10:59:57 +0200397 rc = csd_bs_to_gsm0808_data_rate_non_transp(list->bs[0], &ct->ch_rate_type);
Oliver Smith10632132023-05-12 12:14:22 +0200398 }
399
Oliver Smith17399802023-06-22 10:39:24 +0200400 if (rc < 0)
Oliver Smith10632132023-05-12 12:14:22 +0200401 return -EINVAL;
402
Oliver Smith17399802023-06-22 10:39:24 +0200403 ct->data_rate = rc;
404
Oliver Smith10632132023-05-12 12:14:22 +0200405 /* Other possible data rates allowed (3GPP TS 48.008 ยง 3.2.2.11, 5a) */
406 if (!ct->data_transparent && list->count > 1) {
407 for (i = 1; i < list->count; i++) {
408 if (!csd_bs_is_transp(list->bs[i]))
409 continue;
410
411 rc = csd_bs_to_gsm0808_data_rate_non_transp_allowed(list->bs[i]);
412 if (rc < 0) {
413 LOGP(DMSC, LOGL_DEBUG, "Failed to convert %s to allowed r i/f rate\n",
414 csd_bs_to_str(list->bs[i]));
415 continue;
416 }
417
418 ct->data_rate_allowed |= rc;
419 }
420 if (ct->data_rate_allowed)
421 ct->data_rate_allowed_is_set = true;
422 }
423
Oliver Smith10632132023-05-12 12:14:22 +0200424 return 0;
425}
426
427int csd_bs_list_to_bearer_cap(struct gsm_mncc_bearer_cap *cap, const struct csd_bs_list *list)
428{
429 *cap = (struct gsm_mncc_bearer_cap){
430 .transfer = GSM_MNCC_BCAP_UNR_DIG,
Vadim Yanitskiyab2845a2023-07-26 02:45:24 +0700431 .mode = GSM48_BCAP_TMOD_CIRCUIT,
432 .coding = GSM48_BCAP_CODING_GSM_STD,
433 .radio = GSM48_BCAP_RRQ_FR_ONLY,
Oliver Smith10632132023-05-12 12:14:22 +0200434 };
435 enum csd_bs bs;
436 int i;
437
438 for (i = 0; i < list->count; i++) {
439 bs = list->bs[i];
440
441 cap->data.rate_adaption = GSM48_BCAP_RA_V110_X30;
Vadim Yanitskiyab2845a2023-07-26 02:45:24 +0700442 cap->data.sig_access = GSM48_BCAP_SA_I440_I450;
Oliver Smith10632132023-05-12 12:14:22 +0200443 cap->data.async = bs_map[bs].async;
Vadim Yanitskiyab2845a2023-07-26 02:45:24 +0700444 if (bs_map[bs].transp)
445 cap->data.transp = GSM48_BCAP_TR_TRANSP;
446 else
447 cap->data.transp = GSM48_BCAP_TR_RLP;
448
449 /* FIXME: proper values for sync/async (current: 8N1) */
450 cap->data.nr_data_bits = 8;
451 cap->data.parity = GSM48_BCAP_PAR_NONE;
452 cap->data.nr_stop_bits = 1;
453 cap->data.modem_type = GSM48_BCAP_MT_NONE;
Oliver Smith10632132023-05-12 12:14:22 +0200454
455 switch (bs_map[bs].rate) {
456 case 300:
457 cap->data.user_rate = GSM48_BCAP_UR_300;
Vadim Yanitskiyab2845a2023-07-26 02:45:24 +0700458 cap->data.interm_rate = GSM48_BCAP_IR_8k;
Oliver Smith10632132023-05-12 12:14:22 +0200459 break;
460 case 1200:
461 cap->data.user_rate = GSM48_BCAP_UR_1200;
Vadim Yanitskiyab2845a2023-07-26 02:45:24 +0700462 cap->data.interm_rate = GSM48_BCAP_IR_8k;
Oliver Smith10632132023-05-12 12:14:22 +0200463 break;
464 case 2400:
465 cap->data.user_rate = GSM48_BCAP_UR_2400;
Vadim Yanitskiyab2845a2023-07-26 02:45:24 +0700466 cap->data.interm_rate = GSM48_BCAP_IR_8k;
Oliver Smith10632132023-05-12 12:14:22 +0200467 break;
468 case 4800:
469 cap->data.user_rate = GSM48_BCAP_UR_4800;
Vadim Yanitskiyab2845a2023-07-26 02:45:24 +0700470 cap->data.interm_rate = GSM48_BCAP_IR_8k;
Oliver Smith10632132023-05-12 12:14:22 +0200471 break;
472 case 9600:
473 cap->data.user_rate = GSM48_BCAP_UR_9600;
Vadim Yanitskiyab2845a2023-07-26 02:45:24 +0700474 cap->data.interm_rate = GSM48_BCAP_IR_16k;
Oliver Smith10632132023-05-12 12:14:22 +0200475 break;
Vadim Yanitskiyfc4bc782023-07-26 02:59:47 +0700476 default:
477 LOGP(DMSC, LOGL_ERROR,
478 "%s(): bs=%d (rate=%u) is not implemented\n",
479 __func__, bs, bs_map[bs].rate);
480 continue;
Oliver Smith10632132023-05-12 12:14:22 +0200481 }
482
483 /* FIXME: handle more than one list entry */
484 return 1;
485 }
486
487 return 0;
488}
489
490void csd_bs_list_from_bearer_cap(struct csd_bs_list *list, const struct gsm_mncc_bearer_cap *cap)
491{
492 *list = (struct csd_bs_list){};
493
494 switch (cap->data.transp) {
495 case GSM48_BCAP_TR_TRANSP:
496 csd_bs_list_add_bs(list, csd_bs_from_bearer_cap(cap, true));
497 break;
498 case GSM48_BCAP_TR_RLP: /* NT */
499 csd_bs_list_add_bs(list, csd_bs_from_bearer_cap(cap, false));
500 break;
501 case GSM48_BCAP_TR_TR_PREF:
502 csd_bs_list_add_bs(list, csd_bs_from_bearer_cap(cap, true));
503 csd_bs_list_add_bs(list, csd_bs_from_bearer_cap(cap, false));
504 break;
505 case GSM48_BCAP_TR_RLP_PREF:
506 csd_bs_list_add_bs(list, csd_bs_from_bearer_cap(cap, false));
507 csd_bs_list_add_bs(list, csd_bs_from_bearer_cap(cap, true));
508 break;
509 }
510
511 if (!list->count) {
512 LOGP(DMSC, LOGL_ERROR, "Failed to get bearer service from bearer capabilities ra=%d, async=%d,"
513 " transp=%d, user_rate=%d\n", cap->data.rate_adaption, cap->data.async, cap->data.transp,
514 cap->data.user_rate);
515 return;
516 }
517}