blob: bb403392f905c439c6db9acd4cf70464380056ba [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file gsm_utils.c */
Harald Welteec8b4502010-02-20 20:34:29 +01002/*
3 * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +02004 * (C) 2009,2013 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte622b7182010-03-07 17:50:21 +01005 * (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
Nico Goldec56a56d2012-09-18 14:29:40 +02006 * (C) 2010-2012 by Nico Golde <nico@ngolde.de>
Harald Welteec8b4502010-02-20 20:34:29 +01007 *
8 * All Rights Reserved
9 *
Harald Weltee08da972017-11-13 01:00:26 +090010 * SPDX-License-Identifier: GPL-2.0+
11 *
Harald Welteec8b4502010-02-20 20:34:29 +010012 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
Harald Welteec8b4502010-02-20 20:34:29 +010022 */
23
Harald Welted38c8b82011-08-30 11:32:56 +020024/*! \mainpage libosmogsm Documentation
25 *
26 * \section sec_intro Introduction
27 * This library is a collection of common code used in various
28 * GSM related sub-projects inside the Osmocom family of projects. It
29 * includes A5/1 and A5/2 ciphers, COMP128v1, a LAPDm implementation,
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +020030 * a GSM TLV parser, SMS utility routines as well as
Harald Welted38c8b82011-08-30 11:32:56 +020031 * protocol definitions for a series of protocols:
32 * * Um L2 (04.06)
33 * * Um L3 (04.08)
34 * * A-bis RSL (08.58)
35 * * A-bis OML (08.59, 12.21)
36 * * A (08.08)
37 * \n\n
38 * Please note that C language projects inside Osmocom are typically
39 * single-threaded event-loop state machine designs. As such,
40 * routines in libosmogsm are not thread-safe. If you must use them in
41 * a multi-threaded context, you have to add your own locking.
42 *
Harald Welte71658802017-06-12 15:40:52 +020043 * libosmogsm is developed as part of the Osmocom (Open Source Mobile
44 * Communications) project, a community-based, collaborative development
45 * project to create Free and Open Source implementations of mobile
46 * communications systems. For more information about Osmocom, please
47 * see https://osmocom.org/
48 *
Harald Welted38c8b82011-08-30 11:32:56 +020049 * \section sec_copyright Copyright and License
50 * Copyright © 2008-2011 - Harald Welte, Holger Freyther and contributors\n
51 * All rights reserved. \n\n
52 * The source code of libosmogsm is licensed under the terms of the GNU
53 * General Public License as published by the Free Software Foundation;
54 * either version 2 of the License, or (at your option) any later
55 * version.\n
56 * See <http://www.gnu.org/licenses/> or COPYING included in the source
57 * code package istelf.\n
58 * The information detailed here is provided AS IS with NO WARRANTY OF
59 * ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND
60 * FITNESS FOR A PARTICULAR PURPOSE.
61 * \n\n
62 *
Harald Welte71658802017-06-12 15:40:52 +020063 * \section sec_tracker Homepage + Issue Tracker
64 * libosmogsm is distributed as part of libosmocore and shares its
65 * project page at http://osmocom.org/projects/libosmocore
66 *
67 * An Issue Tracker can be found at
68 * https://osmocom.org/projects/libosmocore/issues
69 *
Harald Welted38c8b82011-08-30 11:32:56 +020070 * \section sec_contact Contact and Support
71 * Community-based support is available at the OpenBSC mailing list
72 * <http://lists.osmocom.org/mailman/listinfo/openbsc>\n
73 * Commercial support options available upon request from
74 * <http://sysmocom.de/>
75 */
76
Harald Welteec8b4502010-02-20 20:34:29 +010077//#include <openbsc/gsm_data.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010078#include <osmocom/core/utils.h>
Max8a5346b2016-04-22 19:28:09 +020079#include <osmocom/core/bitvec.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010080#include <osmocom/gsm/gsm_utils.h>
Max764b0222016-05-11 17:33:17 +020081#include <osmocom/gsm/meas_rep.h>
Max8a5346b2016-04-22 19:28:09 +020082#include <osmocom/gsm/protocol/gsm_04_08.h>
Pau Espin Pedrolaea78a22023-08-11 20:33:38 +020083#include <osmocom/gsm/gsm0502.h>
Harald Welteec8b4502010-02-20 20:34:29 +010084
85#include <stdlib.h>
86#include <stdint.h>
87#include <string.h>
Max764b0222016-05-11 17:33:17 +020088#include <stdbool.h>
Harald Welteec8b4502010-02-20 20:34:29 +010089#include <stdio.h>
90#include <errno.h>
Harald Welteaebe08c2010-03-04 10:39:17 +010091#include <ctype.h>
Pau Espin Pedrol363130f2017-07-03 10:42:42 +020092#include <inttypes.h>
Max4b2b0cc2017-07-10 14:32:48 +020093#include <time.h>
94#include <unistd.h>
Harald Welteec8b4502010-02-20 20:34:29 +010095
Pau Espin Pedrol88955fb2023-01-18 18:54:00 +010096#include "config.h"
Harald Welteec8b4502010-02-20 20:34:29 +010097
Max0187c3a2018-11-09 13:08:42 +010098#if (!EMBEDDED)
Max4b2b0cc2017-07-10 14:32:48 +020099/* FIXME: this can be removed once we bump glibc requirements to 2.25: */
Karl Koscher76f025e2019-03-11 13:19:46 -0700100#ifdef __GLIBC_PREREQ
101#if __GLIBC_PREREQ(2,25)
102#define HAVE_GLIBC_GETRANDOM
103#endif /* if __GLIBC_PREREQ(2,25) */
104#endif /* ifdef __GLIBC_PREREQ */
105#ifdef HAVE_GLIBC_GETRANDOM
Max0187c3a2018-11-09 13:08:42 +0100106#pragma message ("glibc " OSMO_STRINGIFY_VAL(__GLIBC__) "." OSMO_STRINGIFY_VAL(__GLIBC_MINOR__) " random detected")
Pau Espin Pedrole2640ef2017-11-16 16:29:36 +0100107#include <sys/random.h>
Max42e567c2018-11-09 13:13:45 +0100108#undef USE_GNUTLS
Max4b2b0cc2017-07-10 14:32:48 +0200109#elif HAVE_DECL_SYS_GETRANDOM
110#include <sys/syscall.h>
Maxf6245462017-10-09 14:35:03 +0200111#ifndef GRND_NONBLOCK
112#define GRND_NONBLOCK 0x0001
Max0187c3a2018-11-09 13:08:42 +0100113#endif /* ifndef GRND_NONBLOCK */
Karl Koscher76f025e2019-03-11 13:19:46 -0700114#endif /* ifdef HAVE_GLIBC_GETRANDOM */
Max0187c3a2018-11-09 13:08:42 +0100115#endif /* !EMBEDDED */
Max4b2b0cc2017-07-10 14:32:48 +0200116
Maxed029df2017-10-26 10:56:04 +0200117#if (USE_GNUTLS)
118#pragma message ("including GnuTLS for getrandom fallback.")
119#include <gnutls/gnutls.h>
120#include <gnutls/crypto.h>
Alexander Couzens500d6332018-04-24 14:00:24 +0200121
122/* gnutls < 3.3.0 requires global init.
123 * gnutls >= 3.3.0 does it automatic.
124 * It doesn't hurt calling it twice,
125 * as long it's not done at the same time (threads).
126 */
127__attribute__((constructor))
128static void on_dso_load_gnutls(void)
129{
130 if (!gnutls_check_version("3.3.0"))
131 gnutls_global_init();
132}
133
134__attribute__((destructor))
135static void on_dso_unload_gnutls(void)
136{
137 if (!gnutls_check_version("3.3.0"))
138 gnutls_global_deinit();
139}
Max0187c3a2018-11-09 13:08:42 +0100140
141#endif /* if (USE_GNUTLS) */
Maxed029df2017-10-26 10:56:04 +0200142
Holger Hans Peter Freytherdd02a472010-07-23 16:35:00 +0800143/* ETSI GSM 03.38 6.2.1 and 6.2.1.1 default alphabet
144 * Greek symbols at hex positions 0x10 and 0x12-0x1a
145 * left out as they can't be handled with a char and
146 * since most phones don't display or write these
147 * characters this would only needlessly make the code
Jacob Erlbeck18109252013-08-12 17:07:54 +0200148 * more complex.
149 *
150 * Note that this table contains the latin1->7bit mapping _and_ has
151 * been merged with the reverse mapping (7bit->latin1) for the
152 * extended characters at offset 0x7f.
153 */
Holger Hans Peter Freytherdd02a472010-07-23 16:35:00 +0800154static unsigned char gsm_7bit_alphabet[] = {
155 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0x0d, 0xff,
156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
157 0xff, 0xff, 0x20, 0x21, 0x22, 0x23, 0x02, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
158 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
159 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
160 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
161 0x5a, 0x3c, 0x2f, 0x3e, 0x14, 0x11, 0xff, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
162 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
163 0x78, 0x79, 0x7a, 0x28, 0x40, 0x29, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
164 0xff, 0xff, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff,
165 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0xff, 0x01, 0xff,
166 0x03, 0xff, 0x7b, 0x7d, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff,
167 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5b, 0x7e, 0x5d, 0xff, 0x7c, 0xff, 0xff, 0xff,
168 0xff, 0x5b, 0x0e, 0x1c, 0x09, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5d,
169 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0x0b, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff, 0x1e, 0x7f,
170 0xff, 0xff, 0xff, 0x7b, 0x0f, 0x1d, 0xff, 0x04, 0x05, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff,
171 0xff, 0x7d, 0x08, 0xff, 0xff, 0xff, 0x7c, 0xff, 0x0c, 0x06, 0xff, 0xff, 0x7e, 0xff, 0xff
172};
173
Nico Golde28de0532010-07-09 17:19:12 +0200174/* GSM 03.38 6.2.1 Character lookup for decoding */
175static int gsm_septet_lookup(uint8_t ch)
176{
177 int i = 0;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200178 for (; i < sizeof(gsm_7bit_alphabet); i++) {
179 if (gsm_7bit_alphabet[i] == ch)
Nico Golde28de0532010-07-09 17:19:12 +0200180 return i;
181 }
182 return -1;
183}
184
Vadim Yanitskiyed8e2632019-04-07 03:20:55 +0700185/*! Compute number of octets from number of septets.
186 * For instance: 47 septets need 41,125 = 42 octets.
187 * \param[in] sept_len Number of septets
188 * \returns Number of octets required */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200189uint8_t gsm_get_octet_len(const uint8_t sept_len){
190 int octet_len = (sept_len * 7) / 8;
191 if ((sept_len * 7) % 8 != 0)
192 octet_len++;
193
194 return octet_len;
195}
196
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200197/*! TS 03.38 7-bit Character unpacking (6.2.1)
Harald Welte96e2a002017-06-12 21:44:18 +0200198 * \param[out] text Caller-provided output text buffer
199 * \param[in] n Length of \a text
200 * \param[in] user_data Input Data (septets)
201 * \param[in] septet_l Number of septets in \a user_data
202 * \param[in] ud_hdr_ind User Data Header present in data
203 * \returns number of bytes written to \a text */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200204int gsm_7bit_decode_n_hdr(char *text, size_t n, const uint8_t *user_data, uint8_t septet_l, uint8_t ud_hdr_ind)
Harald Welteec8b4502010-02-20 20:34:29 +0100205{
Maxcf37c4c2016-01-21 16:52:40 +0100206 unsigned shift = 0;
207 uint8_t c7, c8, next_is_ext = 0, lu, ru;
208 const uint8_t maxlen = gsm_get_octet_len(septet_l);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200209 const char *text_buf_begin = text;
210 const char *text_buf_end = text + n;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200211
212 OSMO_ASSERT (n > 0);
Harald Welteec8b4502010-02-20 20:34:29 +0100213
Dennis Wehrle291e6132011-07-24 20:14:13 +0200214 /* skip the user data header */
215 if (ud_hdr_ind) {
216 /* get user data header length + 1 (for the 'user data header length'-field) */
217 shift = ((user_data[0] + 1) * 8) / 7;
218 if ((((user_data[0] + 1) * 8) % 7) != 0)
219 shift++;
220 septet_l = septet_l - shift;
221 }
222
Maxcf37c4c2016-01-21 16:52:40 +0100223 unsigned i, l, r;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200224 for (i = 0; i < septet_l && text != text_buf_end - 1; i++) {
Maxcf37c4c2016-01-21 16:52:40 +0100225
226 l = ((i + shift) * 7 + 7) >> 3;
227 r = ((i + shift) * 7) >> 3;
228
229 /* the left side index is always >= right side index
230 sometimes it even gets beyond array boundary
231 check for that explicitly and force 0 instead
232 */
233 if (l >= maxlen)
234 lu = 0;
235 else
236 lu = user_data[l] << (7 - (((i + shift) * 7 + 7) & 7));
237
238 ru = user_data[r] >> (((i + shift) * 7) & 7);
239
240 c7 = (lu | ru) & 0x7f;
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200241
Harald Weltebe55a8b2012-09-20 10:00:25 +0200242 if (next_is_ext) {
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200243 /* this is an extension character */
Nico Goldec56a56d2012-09-18 14:29:40 +0200244 next_is_ext = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200245 c8 = gsm_7bit_alphabet[0x7f + c7];
246 } else if (c7 == 0x1b && i + 1 < septet_l) {
247 next_is_ext = 1;
Nico Golde5b67a042012-09-20 16:56:23 +0200248 continue;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200249 } else {
250 c8 = gsm_septet_lookup(c7);
Nico Golde5b67a042012-09-20 16:56:23 +0200251 }
252
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200253 *(text++) = c8;
Harald Welteec8b4502010-02-20 20:34:29 +0100254 }
255
Nico Golde28de0532010-07-09 17:19:12 +0200256 *text = '\0';
Nico Golde28de0532010-07-09 17:19:12 +0200257
Maxcf37c4c2016-01-21 16:52:40 +0100258 return text - text_buf_begin;
Nico Golde28de0532010-07-09 17:19:12 +0200259}
260
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200261/*! Decode 7bit GSM Alphabet */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200262int gsm_7bit_decode_n(char *text, size_t n, const uint8_t *user_data, uint8_t septet_l)
Dennis Wehrle291e6132011-07-24 20:14:13 +0200263{
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200264 return gsm_7bit_decode_n_hdr(text, n, user_data, septet_l, 0);
Dennis Wehrle291e6132011-07-24 20:14:13 +0200265}
266
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200267/*! Decode 7bit GSM Alphabet (USSD) */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200268int gsm_7bit_decode_n_ussd(char *text, size_t n, const uint8_t *user_data, uint8_t length)
Andreas Eversberg95975552013-08-08 12:38:53 +0200269{
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200270 int nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +0200271
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200272 nchars = gsm_7bit_decode_n_hdr(text, n, user_data, length, 0);
Andreas Eversberg95975552013-08-08 12:38:53 +0200273 /* remove last <CR>, if it fits up to the end of last octet */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200274 if (nchars && (user_data[gsm_get_octet_len(length) - 1] >> 1) == '\r')
275 text[--nchars] = '\0';
Andreas Eversberg95975552013-08-08 12:38:53 +0200276
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200277 return nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +0200278}
279
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200280/*! Encode a ASCII characterrs as 7-bit GSM alphabet (TS 03.38)
Harald Welte96e2a002017-06-12 21:44:18 +0200281 *
282 * This function converts a zero-terminated input string \a data from
283 * ASCII into octet-aligned 7-bit GSM characters. No packing is
284 * performed.
285 *
286 * \param[out] result caller-allocated output buffer
287 * \param[in] data input data, ASCII
288 * \returns number of octets used in \a result */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200289int gsm_septet_encode(uint8_t *result, const char *data)
Nico Golde28de0532010-07-09 17:19:12 +0200290{
291 int i, y = 0;
292 uint8_t ch;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200293 for (i = 0; i < strlen(data); i++) {
Nico Golde28de0532010-07-09 17:19:12 +0200294 ch = data[i];
295 switch(ch){
296 /* fall-through for extension characters */
297 case 0x0c:
298 case 0x5e:
299 case 0x7b:
300 case 0x7d:
301 case 0x5c:
302 case 0x5b:
303 case 0x7e:
304 case 0x5d:
305 case 0x7c:
306 result[y++] = 0x1b;
Vadim Yanitskiy46914742019-04-12 22:42:42 +0700307 /* fall-through */
Nico Golde28de0532010-07-09 17:19:12 +0200308 default:
309 result[y] = gsm_7bit_alphabet[ch];
310 break;
311 }
312 y++;
313 }
314
315 return y;
316}
317
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200318/*! GSM Default Alphabet 7bit to octet packing
Harald Welte96e2a002017-06-12 21:44:18 +0200319 * \param[out] result Caller-provided output buffer
320 * \param[in] rdata Input data septets
321 * \param[in] septet_len Length of \a rdata
322 * \param[in] padding padding bits at start
323 * \returns number of bytes used in \a result */
Vadim Yanitskiy943133c2021-01-30 01:31:32 +0100324int gsm_septet_pack(uint8_t *result, const uint8_t *rdata, size_t septet_len, uint8_t padding)
Harald Welteca693882013-03-13 15:10:55 +0100325{
Dennis Wehrle291e6132011-07-24 20:14:13 +0200326 int i = 0, z = 0;
Nico Golde28de0532010-07-09 17:19:12 +0200327 uint8_t cb, nb;
328 int shift = 0;
Vadim Yanitskiy846db1b2021-01-30 01:22:03 +0100329 uint8_t *data = malloc(septet_len + 1);
Nico Golde28de0532010-07-09 17:19:12 +0200330
Dennis Wehrle291e6132011-07-24 20:14:13 +0200331 if (padding) {
332 shift = 7 - padding;
333 /* the first zero is needed for padding */
334 memcpy(data + 1, rdata, septet_len);
Vadim Yanitskiy846db1b2021-01-30 01:22:03 +0100335 data[0] = 0x00;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200336 septet_len++;
337 } else
338 memcpy(data, rdata, septet_len);
Nico Golde28de0532010-07-09 17:19:12 +0200339
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200340 for (i = 0; i < septet_len; i++) {
Dennis Wehrle291e6132011-07-24 20:14:13 +0200341 if (shift == 7) {
342 /*
343 * special end case with the. This is necessary if the
344 * last septet fits into the previous octet. E.g. 48
345 * non-extension characters:
346 * ....ag ( a = 1100001, g = 1100111)
347 * result[40] = 100001 XX, result[41] = 1100111 1 */
348 if (i + 1 < septet_len) {
349 shift = 0;
350 continue;
351 } else if (i + 1 == septet_len)
352 break;
Nico Golde28de0532010-07-09 17:19:12 +0200353 }
354
Dennis Wehrle291e6132011-07-24 20:14:13 +0200355 cb = (data[i] & 0x7f) >> shift;
356 if (i + 1 < septet_len) {
357 nb = (data[i + 1] & 0x7f) << (7 - shift);
Nico Golde28de0532010-07-09 17:19:12 +0200358 cb = cb | nb;
359 }
360
361 result[z++] = cb;
Nico Golde28de0532010-07-09 17:19:12 +0200362 shift++;
363 }
364
Dennis Wehrle291e6132011-07-24 20:14:13 +0200365 free(data);
366
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200367 return z;
Harald Welteec8b4502010-02-20 20:34:29 +0100368}
369
Vadim Yanitskiy943133c2021-01-30 01:31:32 +0100370/*! Backwards compatibility wrapper for gsm_septets_pack(), deprecated. */
371int gsm_septets2octets(uint8_t *result, const uint8_t *rdata, uint8_t septet_len, uint8_t padding)
372{
373 return gsm_septet_pack(result, rdata, septet_len, padding);
374}
375
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200376/*! GSM 7-bit alphabet TS 03.38 6.2.1 Character packing
Harald Welte96e2a002017-06-12 21:44:18 +0200377 * \param[out] result Caller-provided output buffer
378 * \param[in] n Maximum length of \a result in bytes
379 * \param[in] data octet-aligned string
380 * \param[out] octets Number of octets encoded
381 * \returns number of septets encoded */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200382int gsm_7bit_encode_n(uint8_t *result, size_t n, const char *data, int *octets)
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +0200383{
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200384 int y = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200385 int o;
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100386 size_t max_septets = n * 8 / 7;
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200387
Dennis Wehrle291e6132011-07-24 20:14:13 +0200388 /* prepare for the worst case, every character expanding to two bytes */
Vadim Yanitskiy846db1b2021-01-30 01:22:03 +0100389 uint8_t *rdata = malloc(strlen(data) * 2);
Dennis Wehrle291e6132011-07-24 20:14:13 +0200390 y = gsm_septet_encode(rdata, data);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200391
392 if (y > max_septets) {
393 /*
394 * Limit the number of septets to avoid the generation
395 * of more than n octets.
396 */
397 y = max_septets;
398 }
399
Vadim Yanitskiy943133c2021-01-30 01:31:32 +0100400 o = gsm_septet_pack(result, rdata, y, 0);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200401
402 if (octets)
403 *octets = o;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200404
405 free(rdata);
406
407 /*
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200408 * We don't care about the number of octets, because they are not
Dennis Wehrle291e6132011-07-24 20:14:13 +0200409 * unique. E.g.:
410 * 1.) 46 non-extension characters + 1 extension character
411 * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets
412 * 2.) 47 non-extension characters
413 * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets
414 * 3.) 48 non-extension characters
415 * => (48 * 7 bit) / 8 bit = 42 octects
416 */
417 return y;
418}
419
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200420/*! Encode according to GSM 7-bit alphabet (TS 03.38 6.2.1) for USSD
Harald Welte96e2a002017-06-12 21:44:18 +0200421 * \param[out] result Caller-provided output buffer
422 * \param[in] n Maximum length of \a result in bytes
423 * \param[in] data octet-aligned string
424 * \param[out] octets Number of octets encoded
425 * \returns number of septets encoded */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200426int gsm_7bit_encode_n_ussd(uint8_t *result, size_t n, const char *data, int *octets)
427{
428 int y;
429
430 y = gsm_7bit_encode_n(result, n, data, octets);
431 /* if last octet contains only one bit, add <CR> */
432 if (((y * 7) & 7) == 1)
433 result[(*octets) - 1] |= ('\r' << 1);
434 /* if last character is <CR> and completely fills last octet, add
435 * another <CR>. */
436 if (y && ((y * 7) & 7) == 0 && (result[(*octets) - 1] >> 1) == '\r' && *octets < n - 1) {
437 result[(*octets)++] = '\r';
438 y++;
439 }
440
441 return y;
442}
443
Max4b2b0cc2017-07-10 14:32:48 +0200444/*! Generate random identifier
445 * We use /dev/urandom (default when GRND_RANDOM flag is not set).
446 * Both /dev/(u)random numbers are coming from the same CSPRNG anyway (at least on GNU/Linux >= 4.8).
447 * See also RFC4086.
448 * \param[out] out Buffer to be filled with random data
449 * \param[in] len Number of random bytes required
450 * \returns 0 on success, or a negative error code on error.
451 */
452int osmo_get_rand_id(uint8_t *out, size_t len)
453{
Maxed029df2017-10-26 10:56:04 +0200454 int rc = -ENOTSUP;
Max4b2b0cc2017-07-10 14:32:48 +0200455
456 /* this function is intended for generating short identifiers only, not arbitrary-length random data */
457 if (len > OSMO_MAX_RAND_ID_LEN)
458 return -E2BIG;
Max0187c3a2018-11-09 13:08:42 +0100459#if (!EMBEDDED)
Karl Koscher76f025e2019-03-11 13:19:46 -0700460#ifdef HAVE_GLIBC_GETRANDOM
Max4b2b0cc2017-07-10 14:32:48 +0200461 rc = getrandom(out, len, GRND_NONBLOCK);
462#elif HAVE_DECL_SYS_GETRANDOM
463#pragma message ("Using direct syscall access for getrandom(): consider upgrading to glibc >= 2.25")
464 /* FIXME: this can be removed once we bump glibc requirements to 2.25: */
465 rc = syscall(SYS_getrandom, out, len, GRND_NONBLOCK);
Max4b2b0cc2017-07-10 14:32:48 +0200466#endif
Max0187c3a2018-11-09 13:08:42 +0100467#endif /* !EMBEDDED */
Maxed029df2017-10-26 10:56:04 +0200468
Max4b2b0cc2017-07-10 14:32:48 +0200469 /* getrandom() failed entirely: */
Maxed029df2017-10-26 10:56:04 +0200470 if (rc < 0) {
471#if (USE_GNUTLS)
Maxed029df2017-10-26 10:56:04 +0200472 return gnutls_rnd(GNUTLS_RND_RANDOM, out, len);
Harald Weltedd0d76b2019-07-21 12:08:22 +0200473#else
Max4b2b0cc2017-07-10 14:32:48 +0200474 return -errno;
Harald Weltedd0d76b2019-07-21 12:08:22 +0200475#endif
Maxed029df2017-10-26 10:56:04 +0200476 }
Max4b2b0cc2017-07-10 14:32:48 +0200477
478 /* getrandom() failed partially due to signal interruption:
479 this should never happen (according to getrandom(2)) as long as OSMO_MAX_RAND_ID_LEN < 256
480 because we do not set GRND_RANDOM but it's better to be paranoid and check anyway */
481 if (rc != len)
482 return -EAGAIN;
483
484 return 0;
485}
486
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200487/*! Build the RSL uplink measurement IE (3GPP TS 08.58 § 9.3.25)
Max764b0222016-05-11 17:33:17 +0200488 * \param[in] mru Unidirectional measurement report structure
489 * \param[in] dtxd_used Indicates if DTXd was used during measurement report
490 * period
491 * \param[out] buf Pre-allocated bufer for storing IE
492 * \returns Number of bytes filled in buf
493 */
Pau Espin Pedrol50e6f062021-09-28 11:32:00 +0200494size_t gsm0858_rsl_ul_meas_enc(const struct gsm_meas_rep_unidir *mru, bool dtxd_used,
Max764b0222016-05-11 17:33:17 +0200495 uint8_t *buf)
496{
497 buf[0] = dtxd_used ? (1 << 6) : 0;
498 buf[0] |= (mru->full.rx_lev & 0x3f);
499 buf[1] = (mru->sub.rx_lev & 0x3f);
500 buf[2] = ((mru->full.rx_qual & 7) << 3) | (mru->sub.rx_qual & 7);
501
502 return 3;
503}
504
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200505/*! Convert power class to dBm according to GSM TS 05.05
Harald Welte96e2a002017-06-12 21:44:18 +0200506 * \param[in] band GSM frequency band
507 * \param[in] class GSM power class
Pau Espin Pedrole40b9632019-10-31 15:38:30 +0100508 * \returns maximum transmit power of power class in dBm, negative on error */
509int ms_class_gmsk_dbm(enum gsm_band band, int class)
Andreas Eversberg2a68c7c2011-06-26 11:41:48 +0200510{
511 switch (band) {
512 case GSM_BAND_450:
513 case GSM_BAND_480:
514 case GSM_BAND_750:
515 case GSM_BAND_900:
516 case GSM_BAND_810:
517 case GSM_BAND_850:
518 if (class == 1)
519 return 43; /* 20W */
520 if (class == 2)
521 return 39; /* 8W */
522 if (class == 3)
523 return 37; /* 5W */
524 if (class == 4)
525 return 33; /* 2W */
526 if (class == 5)
527 return 29; /* 0.8W */
528 break;
529 case GSM_BAND_1800:
530 if (class == 1)
531 return 30; /* 1W */
532 if (class == 2)
533 return 24; /* 0.25W */
534 if (class == 3)
535 return 36; /* 4W */
536 break;
537 case GSM_BAND_1900:
538 if (class == 1)
539 return 30; /* 1W */
540 if (class == 2)
541 return 24; /* 0.25W */
542 if (class == 3)
543 return 33; /* 2W */
544 break;
545 }
546 return -EINVAL;
547}
548
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200549/*! determine power control level for given dBm value, as indicated
Harald Welte96e2a002017-06-12 21:44:18 +0200550 * by the tables in chapter 4.1.1 of GSM TS 05.05
551 * \param[in] GSM frequency band
552 * \param[in] dbm RF power value in dBm
553 * \returns TS 05.05 power control level */
Harald Welteec8b4502010-02-20 20:34:29 +0100554int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
555{
556 switch (band) {
557 case GSM_BAND_450:
558 case GSM_BAND_480:
559 case GSM_BAND_750:
560 case GSM_BAND_900:
561 case GSM_BAND_810:
562 case GSM_BAND_850:
563 if (dbm >= 39)
564 return 0;
565 else if (dbm < 5)
566 return 19;
567 else {
568 /* we are guaranteed to have (5 <= dbm < 39) */
569 return 2 + ((39 - dbm) / 2);
570 }
571 break;
572 case GSM_BAND_1800:
573 if (dbm >= 36)
574 return 29;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200575 else if (dbm >= 34)
Harald Welteec8b4502010-02-20 20:34:29 +0100576 return 30;
577 else if (dbm >= 32)
578 return 31;
579 else if (dbm == 31)
580 return 0;
581 else {
582 /* we are guaranteed to have (0 <= dbm < 31) */
583 return (30 - dbm) / 2;
584 }
585 break;
586 case GSM_BAND_1900:
587 if (dbm >= 33)
588 return 30;
589 else if (dbm >= 32)
590 return 31;
591 else if (dbm == 31)
592 return 0;
593 else {
594 /* we are guaranteed to have (0 <= dbm < 31) */
595 return (30 - dbm) / 2;
596 }
597 break;
598 }
599 return -EINVAL;
600}
601
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200602/*! Convert TS 05.05 power level to absolute dBm value
Harald Welte96e2a002017-06-12 21:44:18 +0200603 * \param[in] band GSM frequency band
604 * \param[in] lvl TS 05.05 power control level
605 * \returns RF power level in dBm */
Harald Welteec8b4502010-02-20 20:34:29 +0100606int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
607{
608 lvl &= 0x1f;
609
610 switch (band) {
611 case GSM_BAND_450:
612 case GSM_BAND_480:
613 case GSM_BAND_750:
614 case GSM_BAND_900:
615 case GSM_BAND_810:
616 case GSM_BAND_850:
617 if (lvl < 2)
618 return 39;
619 else if (lvl < 20)
620 return 39 - ((lvl - 2) * 2) ;
621 else
622 return 5;
623 break;
624 case GSM_BAND_1800:
625 if (lvl < 16)
626 return 30 - (lvl * 2);
627 else if (lvl < 29)
628 return 0;
629 else
630 return 36 - ((lvl - 29) * 2);
631 break;
632 case GSM_BAND_1900:
633 if (lvl < 16)
634 return 30 - (lvl * 2);
635 else if (lvl < 30)
636 return -EINVAL;
637 else
638 return 33 - (lvl - 30);
639 break;
640 }
641 return -EINVAL;
642}
643
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200644/*! Convert TS 05.08 RxLev to dBm (TS 05.08 Chapter 8.1.4)
Harald Welte96e2a002017-06-12 21:44:18 +0200645 * \param[in] rxlev TS 05.08 RxLev value
646 * \returns Received RF power in dBm */
Harald Welteec8b4502010-02-20 20:34:29 +0100647int rxlev2dbm(uint8_t rxlev)
648{
649 if (rxlev > 63)
650 rxlev = 63;
651
652 return -110 + rxlev;
653}
654
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200655/*! Convert RF signal level in dBm to TS 05.08 RxLev (TS 05.08 Chapter 8.1.4)
Harald Welte96e2a002017-06-12 21:44:18 +0200656 * \param[in] dbm RF signal level in dBm
657 * \returns TS 05.08 RxLev value */
Harald Welteec8b4502010-02-20 20:34:29 +0100658uint8_t dbm2rxlev(int dbm)
659{
660 int rxlev = dbm + 110;
661
662 if (rxlev > 63)
663 rxlev = 63;
664 else if (rxlev < 0)
665 rxlev = 0;
666
667 return rxlev;
668}
669
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200670/*! Return string name of a given GSM Band */
Harald Weltecbc80622010-03-22 08:28:44 +0800671const char *gsm_band_name(enum gsm_band band)
Harald Welteaebe08c2010-03-04 10:39:17 +0100672{
673 switch (band) {
674 case GSM_BAND_450:
675 return "GSM450";
676 case GSM_BAND_480:
Sylvain Munaute10ae5b2010-07-04 11:41:36 +0200677 return "GSM480";
Harald Welteaebe08c2010-03-04 10:39:17 +0100678 case GSM_BAND_750:
679 return "GSM750";
680 case GSM_BAND_810:
681 return "GSM810";
682 case GSM_BAND_850:
683 return "GSM850";
684 case GSM_BAND_900:
685 return "GSM900";
686 case GSM_BAND_1800:
687 return "DCS1800";
688 case GSM_BAND_1900:
689 return "PCS1900";
690 }
691 return "invalid";
692}
693
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200694/*! Parse string name of a GSM band */
Harald Welteaebe08c2010-03-04 10:39:17 +0100695enum gsm_band gsm_band_parse(const char* mhz)
696{
Pau Espin Pedrol399a6f02017-06-18 14:07:37 +0200697 while (*mhz && !isdigit((unsigned char)*mhz))
Harald Welteaebe08c2010-03-04 10:39:17 +0100698 mhz++;
699
700 if (*mhz == '\0')
701 return -EINVAL;
702
Harald Welted3ff15f2010-03-07 18:23:47 +0100703 switch (strtol(mhz, NULL, 10)) {
Harald Welteaebe08c2010-03-04 10:39:17 +0100704 case 450:
705 return GSM_BAND_450;
706 case 480:
707 return GSM_BAND_480;
708 case 750:
709 return GSM_BAND_750;
710 case 810:
711 return GSM_BAND_810;
712 case 850:
713 return GSM_BAND_850;
714 case 900:
715 return GSM_BAND_900;
716 case 1800:
717 return GSM_BAND_1800;
718 case 1900:
719 return GSM_BAND_1900;
720 default:
721 return -EINVAL;
722 }
723}
724
Pau Espin Pedrolc8772512018-11-16 12:59:46 +0100725/*! Resolve GSM band from ARFCN.
Harald Welte96e2a002017-06-12 21:44:18 +0200726 * In Osmocom, we use the highest bit of the \a arfcn to indicate PCS
727 * \param[in] arfcn Osmocom ARFCN, highest bit determines PCS mode
Pau Espin Pedrolc8772512018-11-16 12:59:46 +0100728 * \param[out] band GSM Band containing \arfcn if arfcn is valid, undetermined otherwise
729 * \returns 0 if arfcn is valid and \a band was set, negative on error */
730int gsm_arfcn2band_rc(uint16_t arfcn, enum gsm_band *band)
Harald Welte622b7182010-03-07 17:50:21 +0100731{
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100732 int is_pcs = arfcn & ARFCN_PCS;
733
734 arfcn &= ~ARFCN_FLAG_MASK;
735
Pau Espin Pedrolc8772512018-11-16 12:59:46 +0100736 if (is_pcs) {
737 *band = GSM_BAND_1900;
738 return 0;
739 } else if (arfcn <= 124) {
740 *band = GSM_BAND_900;
741 return 0;
742 } else if (arfcn >= 955 && arfcn <= 1023) {
743 *band = GSM_BAND_900;
744 return 0;
745 } else if (arfcn >= 128 && arfcn <= 251) {
746 *band = GSM_BAND_850;
747 return 0;
748 } else if (arfcn >= 512 && arfcn <= 885) {
749 *band = GSM_BAND_1800;
750 return 0;
751 } else if (arfcn >= 259 && arfcn <= 293) {
752 *band = GSM_BAND_450;
753 return 0;
754 } else if (arfcn >= 306 && arfcn <= 340) {
755 *band = GSM_BAND_480;
756 return 0;
757 } else if (arfcn >= 350 && arfcn <= 425) {
758 *band = GSM_BAND_810;
759 return 0;
760 } else if (arfcn >= 438 && arfcn <= 511) {
761 *band = GSM_BAND_750;
762 return 0;
763 }
764 return -1;
765}
766
767/*! Resolve GSM band from ARFCN, aborts process on invalid ARFCN.
768 * In Osmocom, we use the highest bit of the \a arfcn to indicate PCS.
769 * DEPRECATED: Use gsm_arfcn2band_rc instead.
770 * \param[in] arfcn Osmocom ARFCN, highest bit determines PCS mode
771 * \returns GSM Band if ARFCN is valid (part of any valid band), aborts otherwise */
772enum gsm_band gsm_arfcn2band(uint16_t arfcn)
773{
774 enum gsm_band band;
775 if (gsm_arfcn2band_rc(arfcn, &band) == 0)
776 return band;
777
778 osmo_panic("%s:%d Invalid arfcn %" PRIu16 " passed to gsm_arfcn2band\n",
779 __FILE__, __LINE__, arfcn);
Harald Welte622b7182010-03-07 17:50:21 +0100780}
781
Sylvain Munaut55720312012-12-11 23:44:41 +0100782struct gsm_freq_range {
783 uint16_t arfcn_first;
784 uint16_t arfcn_last;
785 uint16_t freq_ul_first;
786 uint16_t freq_dl_offset;
787 uint16_t flags;
788};
789
790static struct gsm_freq_range gsm_ranges[] = {
791 { 512, 810, 18502, 800, ARFCN_PCS }, /* PCS 1900 */
792 { 0, 124, 8900, 450, 0 }, /* P-GSM + E-GSM ARFCN 0 */
793 { 955, 1023, 8762, 450, 0 }, /* E-GSM + R-GSM */
794 { 128, 251, 8242, 450, 0 }, /* GSM 850 */
795 { 512, 885, 17102, 950, 0 }, /* DCS 1800 */
796 { 259, 293, 4506, 100, 0 }, /* GSM 450 */
797 { 306, 340, 4790, 100, 0 }, /* GSM 480 */
798 { 350, 425, 8060, 450, 0 }, /* GSM 810 */
799 { 438, 511, 7472, 300, 0 }, /* GSM 750 */
800 { /* Guard */ }
801};
802
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200803/*! Convert an ARFCN to the frequency in MHz * 10
Harald Welte96e2a002017-06-12 21:44:18 +0200804 * \param[in] arfcn GSM ARFCN to convert
805 * \param[in] uplink Uplink (1) or Downlink (0) frequency
806 * \returns Frequency in units of 1/10ths of MHz (100kHz) */
Harald Welte622b7182010-03-07 17:50:21 +0100807uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
808{
Sylvain Munaut55720312012-12-11 23:44:41 +0100809 struct gsm_freq_range *r;
810 uint16_t flags = arfcn & ARFCN_FLAG_MASK;
811 uint16_t freq10_ul = 0xffff;
812 uint16_t freq10_dl = 0xffff;
Harald Welte622b7182010-03-07 17:50:21 +0100813
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100814 arfcn &= ~ARFCN_FLAG_MASK;
815
Sylvain Munaut55720312012-12-11 23:44:41 +0100816 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
817 if ((flags == r->flags) &&
818 (arfcn >= r->arfcn_first) &&
819 (arfcn <= r->arfcn_last))
820 {
821 freq10_ul = r->freq_ul_first + 2 * (arfcn - r->arfcn_first);
822 freq10_dl = freq10_ul + r->freq_dl_offset;
823 break;
824 }
825 }
826
827 return uplink ? freq10_ul : freq10_dl;
828}
829
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200830/*! Convert a Frequency in MHz * 10 to ARFCN
Harald Welte96e2a002017-06-12 21:44:18 +0200831 * \param[in] freq10 Frequency in units of 1/10ths of MHz (100kHz)
832 * \param[in] uplink Frequency is Uplink (1) or Downlink (0)
833 * \returns ARFCN in case of success; 0xffff on error */
Sylvain Munaut55720312012-12-11 23:44:41 +0100834uint16_t gsm_freq102arfcn(uint16_t freq10, int uplink)
835{
836 struct gsm_freq_range *r;
837 uint16_t freq10_lo, freq10_hi;
838 uint16_t arfcn = 0xffff;
839
840 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
841 /* Generate frequency limits */
842 freq10_lo = r->freq_ul_first;
843 freq10_hi = freq10_lo + 2 * (r->arfcn_last - r->arfcn_first);
844 if (!uplink) {
845 freq10_lo += r->freq_dl_offset;
846 freq10_hi += r->freq_dl_offset;
847 }
848
849 /* Check if this fits */
850 if (freq10 >= freq10_lo && freq10 <= freq10_hi) {
851 arfcn = r->arfcn_first + ((freq10 - freq10_lo) >> 1);
852 arfcn |= r->flags;
853 break;
854 }
855 }
Harald Welte622b7182010-03-07 17:50:21 +0100856
857 if (uplink)
Sylvain Munaut55720312012-12-11 23:44:41 +0100858 arfcn |= ARFCN_UPLINK;
859
860 return arfcn;
Harald Welte622b7182010-03-07 17:50:21 +0100861}
862
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200863/*! Parse GSM Frame Number into struct \ref gsm_time
Harald Welte96e2a002017-06-12 21:44:18 +0200864 * \param[out] time Caller-provided memory for \ref gsm_time
865 * \param[in] fn GSM Frame Number */
Harald Welte622b7182010-03-07 17:50:21 +0100866void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
867{
868 time->fn = fn;
869 time->t1 = time->fn / (26*51);
870 time->t2 = time->fn % 26;
871 time->t3 = time->fn % 51;
872 time->tc = (time->fn / 51) % 8;
873}
874
Philipp Maierb808da42017-06-26 10:50:28 +0200875/*! Parse GSM Frame Number into printable string
876 * \param[in] fn GSM Frame Number
877 * \returns pointer to printable string */
878char *gsm_fn_as_gsmtime_str(uint32_t fn)
879{
880 struct gsm_time time;
881
882 gsm_fn2gsmtime(&time, fn);
883 return osmo_dump_gsmtime(&time);
884}
885
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200886/*! Encode decoded \ref gsm_time to Frame Number
Harald Welte96e2a002017-06-12 21:44:18 +0200887 * \param[in] time GSM Time in decoded structure
888 * \returns GSM Frame Number */
Pau Espin Pedrol3e5609a2023-03-06 13:59:40 +0100889uint32_t gsm_gsmtime2fn(const struct gsm_time *time)
Harald Welte622b7182010-03-07 17:50:21 +0100890{
Philipp Maiera13d5662023-01-12 12:58:11 +0100891 uint32_t fn;
892
893 /* See also:
894 * 3GPP TS 44.018, section 10.5.2.38, 3GPP TS 45.002 section 4.3.3, and
895 * 3GPP TS 48.058, section 9.3.8 */
896 fn = 51 * OSMO_MOD_FLR((time->t3-time->t2), 26) + time->t3 + 51 * 26 * time->t1;
897
898 /* Note: Corrupted input values may cause a resulting frame number
899 * larger then the maximum permitted value of GSM_MAX_FN. Even though
900 * the caller is expected to check the input values beforehand we must
901 * make sure that the result cannot exceed the value range of a valid
902 * GSM frame number. */
903 return fn % GSM_MAX_FN;
Harald Welte622b7182010-03-07 17:50:21 +0100904}
Harald Weltea1c4f762010-05-01 11:59:42 +0200905
Harald Welte4a62eda2019-03-18 18:27:00 +0100906char *osmo_dump_gsmtime_buf(char *buf, size_t buf_len, const struct gsm_time *tm)
Pau Espin Pedrol363130f2017-07-03 10:42:42 +0200907{
Harald Welte4a62eda2019-03-18 18:27:00 +0100908 snprintf(buf, buf_len, "%06"PRIu32"/%02"PRIu16"/%02"PRIu8"/%02"PRIu8"/%02"PRIu8,
Pau Espin Pedrol363130f2017-07-03 10:42:42 +0200909 tm->fn, tm->t1, tm->t2, tm->t3, (uint8_t)tm->fn%52);
Philipp Maiere8461e42019-04-08 12:07:36 +0200910 buf[buf_len-1] = '\0';
Pau Espin Pedrol363130f2017-07-03 10:42:42 +0200911 return buf;
912}
913
Harald Welte4a62eda2019-03-18 18:27:00 +0100914char *osmo_dump_gsmtime(const struct gsm_time *tm)
915{
Harald Welte171ef822019-03-28 10:49:05 +0100916 static __thread char buf[64];
Harald Welte4a62eda2019-03-18 18:27:00 +0100917 return osmo_dump_gsmtime_buf(buf, sizeof(buf), tm);
918}
919
Harald Welte179f3572019-03-18 18:38:47 +0100920char *osmo_dump_gsmtime_c(const void *ctx, const struct gsm_time *tm)
921{
922 char *buf = talloc_size(ctx, 64);
923 if (!buf)
924 return NULL;
925 return osmo_dump_gsmtime_buf(buf, 64, tm);
926}
Harald Welte4a62eda2019-03-18 18:27:00 +0100927
Pau Espin Pedrolaea78a22023-08-11 20:33:38 +0200928#define GSM_RFN_THRESHOLD (GSM_RFN_MODULUS / 2)
929uint32_t gsm_rfn2fn(uint16_t rfn, uint32_t curr_fn)
930{
931 uint32_t curr_rfn;
932 uint32_t fn_rounded;
933 const uint32_t rfn32 = rfn; /* used as 32bit for calculations */
934
935 /* Ensure that all following calculations are performed with the
936 * relative frame number */
937 OSMO_ASSERT(rfn32 < GSM_RFN_MODULUS);
938
939 /* Compute an internal relative frame number from the full internal
940 frame number */
941 curr_rfn = gsm_fn2rfn(curr_fn);
942
943 /* Compute a "rounded" version of the internal frame number, which
944 * exactly fits in the RFN_MODULUS raster */
945 fn_rounded = GSM_TDMA_FN_SUB(curr_fn, curr_rfn);
946
947 /* If the delta between the internal and the external relative frame
948 * number exceeds a certain limit, we need to assume that the incoming
949 * request belongs to a the previous rfn period. To correct this,
950 * we roll back the rounded frame number by one RFN_MODULUS */
951 if (GSM_TDMA_FN_DIFF(rfn32, curr_rfn) > GSM_RFN_THRESHOLD) {
952 /* Race condition between rfn and curr_fn detected: rfn belongs
953 to the previous RFN_MODULUS cycle, wrapping... */
954 if (fn_rounded < GSM_RFN_MODULUS) {
955 /* Corner case detected: wrapping crosses GSM_MAX_FN border */
956 fn_rounded = GSM_TDMA_FN_SUB(GSM_MAX_FN, (GSM_TDMA_FN_SUB(GSM_RFN_MODULUS, fn_rounded)));
957 } else {
958 fn_rounded = GSM_TDMA_FN_SUB(fn_rounded, GSM_RFN_MODULUS);
959 }
960 }
961
962 /* The real frame number is the sum of the rounded frame number and the
963 * relative framenumber computed via RACH */
964 return GSM_TDMA_FN_SUM(fn_rounded, rfn32);
965}
966
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200967/*! append range1024 encoded data to bit vector
Harald Welte96e2a002017-06-12 21:44:18 +0200968 * \param[out] bv Caller-provided output bit-vector
969 * \param[in] r Input Range1024 sructure */
Max8a5346b2016-04-22 19:28:09 +0200970void bitvec_add_range1024(struct bitvec *bv, const struct gsm48_range_1024 *r)
971{
972 bitvec_set_uint(bv, r->w1_hi, 2);
973 bitvec_set_uint(bv, r->w1_lo, 8);
974 bitvec_set_uint(bv, r->w2_hi, 8);
975 bitvec_set_uint(bv, r->w2_lo, 1);
976 bitvec_set_uint(bv, r->w3_hi, 7);
977 bitvec_set_uint(bv, r->w3_lo, 2);
978 bitvec_set_uint(bv, r->w4_hi, 6);
979 bitvec_set_uint(bv, r->w4_lo, 2);
980 bitvec_set_uint(bv, r->w5_hi, 6);
981 bitvec_set_uint(bv, r->w5_lo, 2);
982 bitvec_set_uint(bv, r->w6_hi, 6);
983 bitvec_set_uint(bv, r->w6_lo, 2);
984 bitvec_set_uint(bv, r->w7_hi, 6);
985 bitvec_set_uint(bv, r->w7_lo, 2);
986 bitvec_set_uint(bv, r->w8_hi, 6);
987 bitvec_set_uint(bv, r->w8_lo, 1);
988 bitvec_set_uint(bv, r->w9, 7);
989 bitvec_set_uint(bv, r->w10, 7);
990 bitvec_set_uint(bv, r->w11_hi, 1);
991 bitvec_set_uint(bv, r->w11_lo, 6);
992 bitvec_set_uint(bv, r->w12_hi, 2);
993 bitvec_set_uint(bv, r->w12_lo, 5);
994 bitvec_set_uint(bv, r->w13_hi, 3);
995 bitvec_set_uint(bv, r->w13_lo, 4);
996 bitvec_set_uint(bv, r->w14_hi, 4);
997 bitvec_set_uint(bv, r->w14_lo, 3);
998 bitvec_set_uint(bv, r->w15_hi, 5);
999 bitvec_set_uint(bv, r->w15_lo, 2);
1000 bitvec_set_uint(bv, r->w16, 6);
1001}
1002
Neels Hofmeyr87e45502017-06-20 00:17:59 +02001003/*! Determine GPRS TLLI Type (TS 23.003 Chapter 2.6) */
Harald Weltea1c4f762010-05-01 11:59:42 +02001004int gprs_tlli_type(uint32_t tlli)
1005{
1006 if ((tlli & 0xc0000000) == 0xc0000000)
1007 return TLLI_LOCAL;
1008 else if ((tlli & 0xc0000000) == 0x80000000)
1009 return TLLI_FOREIGN;
1010 else if ((tlli & 0xf8000000) == 0x78000000)
1011 return TLLI_RANDOM;
1012 else if ((tlli & 0xf8000000) == 0x70000000)
1013 return TLLI_AUXILIARY;
Harald Welte1f6aad12015-08-15 19:51:45 +02001014 else if ((tlli & 0xf0000000) == 0x00000000)
1015 return TLLI_G_RNTI;
1016 else if ((tlli & 0xf0000000) == 0x10000000)
1017 return TLLI_RAND_G_RNTI;
Harald Weltea1c4f762010-05-01 11:59:42 +02001018
1019 return TLLI_RESERVED;
1020}
Harald Weltec2263172010-06-01 10:47:07 +02001021
Neels Hofmeyr87e45502017-06-20 00:17:59 +02001022/*! Determine TLLI from P-TMSI
Harald Welte96e2a002017-06-12 21:44:18 +02001023 * \param[in] p_tmsi P-TMSI
1024 * \param[in] type TLLI Type we want to derive from \a p_tmsi
1025 * \returns TLLI of given type */
Harald Weltec2263172010-06-01 10:47:07 +02001026uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
1027{
1028 uint32_t tlli;
1029 switch (type) {
1030 case TLLI_LOCAL:
1031 tlli = p_tmsi | 0xc0000000;
1032 break;
1033 case TLLI_FOREIGN:
1034 tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
1035 break;
1036 default:
1037 tlli = 0;
1038 break;
1039 }
1040 return tlli;
1041}
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +02001042
1043/* Wrappers for deprecated functions: */
1044
1045int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l)
1046{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +01001047 gsm_7bit_decode_n(text, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
1048 user_data, septet_l);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +02001049
1050 /* Mimic the original behaviour. */
1051 return septet_l;
1052}
1053
1054int gsm_7bit_decode_ussd(char *text, const uint8_t *user_data, uint8_t length)
1055{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +01001056 return gsm_7bit_decode_n_ussd(text, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
1057 user_data, length);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +02001058}
1059
1060int gsm_7bit_encode(uint8_t *result, const char *data)
1061{
1062 int out;
Jacob Erlbeck26cbd452014-01-07 13:39:24 +01001063 return gsm_7bit_encode_n(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
1064 data, &out);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +02001065}
1066
1067int gsm_7bit_encode_ussd(uint8_t *result, const char *data, int *octets)
1068{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +01001069 return gsm_7bit_encode_n_ussd(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
1070 data, octets);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +02001071}
1072
1073int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets)
1074{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +01001075 return gsm_7bit_encode_n(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
1076 data, octets);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +02001077}
Neels Hofmeyr5b5c3492018-12-26 18:03:17 +01001078
1079/* This is also used by osmo-hlr's db schema */
1080const struct value_string osmo_rat_type_names[] = {
1081 { OSMO_RAT_UNKNOWN, "unknown" },
1082 { OSMO_RAT_GERAN_A, "GERAN-A" },
1083 { OSMO_RAT_UTRAN_IU, "UTRAN-Iu" },
Neels Hofmeyr0d39a8d2019-01-04 04:37:00 +01001084 { OSMO_RAT_EUTRAN_SGS, "EUTRAN-SGs" },
Neels Hofmeyr5b5c3492018-12-26 18:03:17 +01001085 {}
1086};