blob: e3f792efbf78f24b1f6f7898a75b7acd8a8d2cdc [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 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 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 General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 *
24 */
25
Harald Welted38c8b82011-08-30 11:32:56 +020026/*! \mainpage libosmogsm Documentation
27 *
28 * \section sec_intro Introduction
29 * This library is a collection of common code used in various
30 * GSM related sub-projects inside the Osmocom family of projects. It
31 * includes A5/1 and A5/2 ciphers, COMP128v1, a LAPDm implementation,
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +020032 * a GSM TLV parser, SMS utility routines as well as
Harald Welted38c8b82011-08-30 11:32:56 +020033 * protocol definitions for a series of protocols:
34 * * Um L2 (04.06)
35 * * Um L3 (04.08)
36 * * A-bis RSL (08.58)
37 * * A-bis OML (08.59, 12.21)
38 * * A (08.08)
39 * \n\n
40 * Please note that C language projects inside Osmocom are typically
41 * single-threaded event-loop state machine designs. As such,
42 * routines in libosmogsm are not thread-safe. If you must use them in
43 * a multi-threaded context, you have to add your own locking.
44 *
Harald Welte71658802017-06-12 15:40:52 +020045 * libosmogsm is developed as part of the Osmocom (Open Source Mobile
46 * Communications) project, a community-based, collaborative development
47 * project to create Free and Open Source implementations of mobile
48 * communications systems. For more information about Osmocom, please
49 * see https://osmocom.org/
50 *
Harald Welted38c8b82011-08-30 11:32:56 +020051 * \section sec_copyright Copyright and License
52 * Copyright © 2008-2011 - Harald Welte, Holger Freyther and contributors\n
53 * All rights reserved. \n\n
54 * The source code of libosmogsm is licensed under the terms of the GNU
55 * General Public License as published by the Free Software Foundation;
56 * either version 2 of the License, or (at your option) any later
57 * version.\n
58 * See <http://www.gnu.org/licenses/> or COPYING included in the source
59 * code package istelf.\n
60 * The information detailed here is provided AS IS with NO WARRANTY OF
61 * ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND
62 * FITNESS FOR A PARTICULAR PURPOSE.
63 * \n\n
64 *
Harald Welte71658802017-06-12 15:40:52 +020065 * \section sec_tracker Homepage + Issue Tracker
66 * libosmogsm is distributed as part of libosmocore and shares its
67 * project page at http://osmocom.org/projects/libosmocore
68 *
69 * An Issue Tracker can be found at
70 * https://osmocom.org/projects/libosmocore/issues
71 *
Harald Welted38c8b82011-08-30 11:32:56 +020072 * \section sec_contact Contact and Support
73 * Community-based support is available at the OpenBSC mailing list
74 * <http://lists.osmocom.org/mailman/listinfo/openbsc>\n
75 * Commercial support options available upon request from
76 * <http://sysmocom.de/>
77 */
78
Harald Welteec8b4502010-02-20 20:34:29 +010079//#include <openbsc/gsm_data.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010080#include <osmocom/core/utils.h>
Max8a5346b2016-04-22 19:28:09 +020081#include <osmocom/core/bitvec.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010082#include <osmocom/gsm/gsm_utils.h>
Max764b0222016-05-11 17:33:17 +020083#include <osmocom/gsm/meas_rep.h>
Max8a5346b2016-04-22 19:28:09 +020084#include <osmocom/gsm/protocol/gsm_04_08.h>
Harald Welteec8b4502010-02-20 20:34:29 +010085
86#include <stdlib.h>
87#include <stdint.h>
88#include <string.h>
Max764b0222016-05-11 17:33:17 +020089#include <stdbool.h>
Harald Welteec8b4502010-02-20 20:34:29 +010090#include <stdio.h>
91#include <errno.h>
Harald Welteaebe08c2010-03-04 10:39:17 +010092#include <ctype.h>
Pau Espin Pedrol363130f2017-07-03 10:42:42 +020093#include <inttypes.h>
Max4b2b0cc2017-07-10 14:32:48 +020094#include <time.h>
95#include <unistd.h>
Harald Welteec8b4502010-02-20 20:34:29 +010096
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010097#include "../../config.h"
Harald Welteec8b4502010-02-20 20:34:29 +010098
Max4b2b0cc2017-07-10 14:32:48 +020099/* FIXME: this can be removed once we bump glibc requirements to 2.25: */
100#if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25)
101#include <linux/random.h>
102#elif HAVE_DECL_SYS_GETRANDOM
103#include <sys/syscall.h>
Maxf6245462017-10-09 14:35:03 +0200104#ifndef GRND_NONBLOCK
105#define GRND_NONBLOCK 0x0001
106#endif
Max4b2b0cc2017-07-10 14:32:48 +0200107#endif
108
Holger Hans Peter Freytherdd02a472010-07-23 16:35:00 +0800109/* ETSI GSM 03.38 6.2.1 and 6.2.1.1 default alphabet
110 * Greek symbols at hex positions 0x10 and 0x12-0x1a
111 * left out as they can't be handled with a char and
112 * since most phones don't display or write these
113 * characters this would only needlessly make the code
Jacob Erlbeck18109252013-08-12 17:07:54 +0200114 * more complex.
115 *
116 * Note that this table contains the latin1->7bit mapping _and_ has
117 * been merged with the reverse mapping (7bit->latin1) for the
118 * extended characters at offset 0x7f.
119 */
Holger Hans Peter Freytherdd02a472010-07-23 16:35:00 +0800120static unsigned char gsm_7bit_alphabet[] = {
121 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0x0d, 0xff,
122 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
123 0xff, 0xff, 0x20, 0x21, 0x22, 0x23, 0x02, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
124 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
125 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
126 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
127 0x5a, 0x3c, 0x2f, 0x3e, 0x14, 0x11, 0xff, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
128 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
129 0x78, 0x79, 0x7a, 0x28, 0x40, 0x29, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
130 0xff, 0xff, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff,
131 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0xff, 0x01, 0xff,
132 0x03, 0xff, 0x7b, 0x7d, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff,
133 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5b, 0x7e, 0x5d, 0xff, 0x7c, 0xff, 0xff, 0xff,
134 0xff, 0x5b, 0x0e, 0x1c, 0x09, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5d,
135 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0x0b, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff, 0x1e, 0x7f,
136 0xff, 0xff, 0xff, 0x7b, 0x0f, 0x1d, 0xff, 0x04, 0x05, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff,
137 0xff, 0x7d, 0x08, 0xff, 0xff, 0xff, 0x7c, 0xff, 0x0c, 0x06, 0xff, 0xff, 0x7e, 0xff, 0xff
138};
139
Nico Golde28de0532010-07-09 17:19:12 +0200140/* GSM 03.38 6.2.1 Character lookup for decoding */
141static int gsm_septet_lookup(uint8_t ch)
142{
143 int i = 0;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200144 for (; i < sizeof(gsm_7bit_alphabet); i++) {
145 if (gsm_7bit_alphabet[i] == ch)
Nico Golde28de0532010-07-09 17:19:12 +0200146 return i;
147 }
148 return -1;
149}
150
Harald Welte96e2a002017-06-12 21:44:18 +0200151/*! \brife Compute number of octets from number of septets,
152 * for instance: 47 septets needs 41,125 = 42 octets
153 * \param[in sept_len Number of Septets
154 * \returns Number of octets required */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200155uint8_t gsm_get_octet_len(const uint8_t sept_len){
156 int octet_len = (sept_len * 7) / 8;
157 if ((sept_len * 7) % 8 != 0)
158 octet_len++;
159
160 return octet_len;
161}
162
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200163/*! TS 03.38 7-bit Character unpacking (6.2.1)
Harald Welte96e2a002017-06-12 21:44:18 +0200164 * \param[out] text Caller-provided output text buffer
165 * \param[in] n Length of \a text
166 * \param[in] user_data Input Data (septets)
167 * \param[in] septet_l Number of septets in \a user_data
168 * \param[in] ud_hdr_ind User Data Header present in data
169 * \returns number of bytes written to \a text */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200170int 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 +0100171{
Maxcf37c4c2016-01-21 16:52:40 +0100172 unsigned shift = 0;
173 uint8_t c7, c8, next_is_ext = 0, lu, ru;
174 const uint8_t maxlen = gsm_get_octet_len(septet_l);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200175 const char *text_buf_begin = text;
176 const char *text_buf_end = text + n;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200177
178 OSMO_ASSERT (n > 0);
Harald Welteec8b4502010-02-20 20:34:29 +0100179
Dennis Wehrle291e6132011-07-24 20:14:13 +0200180 /* skip the user data header */
181 if (ud_hdr_ind) {
182 /* get user data header length + 1 (for the 'user data header length'-field) */
183 shift = ((user_data[0] + 1) * 8) / 7;
184 if ((((user_data[0] + 1) * 8) % 7) != 0)
185 shift++;
186 septet_l = septet_l - shift;
187 }
188
Maxcf37c4c2016-01-21 16:52:40 +0100189 unsigned i, l, r;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200190 for (i = 0; i < septet_l && text != text_buf_end - 1; i++) {
Maxcf37c4c2016-01-21 16:52:40 +0100191
192 l = ((i + shift) * 7 + 7) >> 3;
193 r = ((i + shift) * 7) >> 3;
194
195 /* the left side index is always >= right side index
196 sometimes it even gets beyond array boundary
197 check for that explicitly and force 0 instead
198 */
199 if (l >= maxlen)
200 lu = 0;
201 else
202 lu = user_data[l] << (7 - (((i + shift) * 7 + 7) & 7));
203
204 ru = user_data[r] >> (((i + shift) * 7) & 7);
205
206 c7 = (lu | ru) & 0x7f;
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200207
Harald Weltebe55a8b2012-09-20 10:00:25 +0200208 if (next_is_ext) {
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200209 /* this is an extension character */
Nico Goldec56a56d2012-09-18 14:29:40 +0200210 next_is_ext = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200211 c8 = gsm_7bit_alphabet[0x7f + c7];
212 } else if (c7 == 0x1b && i + 1 < septet_l) {
213 next_is_ext = 1;
Nico Golde5b67a042012-09-20 16:56:23 +0200214 continue;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200215 } else {
216 c8 = gsm_septet_lookup(c7);
Nico Golde5b67a042012-09-20 16:56:23 +0200217 }
218
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200219 *(text++) = c8;
Harald Welteec8b4502010-02-20 20:34:29 +0100220 }
221
Nico Golde28de0532010-07-09 17:19:12 +0200222 *text = '\0';
Nico Golde28de0532010-07-09 17:19:12 +0200223
Maxcf37c4c2016-01-21 16:52:40 +0100224 return text - text_buf_begin;
Nico Golde28de0532010-07-09 17:19:12 +0200225}
226
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200227/*! Decode 7bit GSM Alphabet */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200228int 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 +0200229{
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200230 return gsm_7bit_decode_n_hdr(text, n, user_data, septet_l, 0);
Dennis Wehrle291e6132011-07-24 20:14:13 +0200231}
232
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200233/*! Decode 7bit GSM Alphabet (USSD) */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200234int 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 +0200235{
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200236 int nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +0200237
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200238 nchars = gsm_7bit_decode_n_hdr(text, n, user_data, length, 0);
Andreas Eversberg95975552013-08-08 12:38:53 +0200239 /* remove last <CR>, if it fits up to the end of last octet */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200240 if (nchars && (user_data[gsm_get_octet_len(length) - 1] >> 1) == '\r')
241 text[--nchars] = '\0';
Andreas Eversberg95975552013-08-08 12:38:53 +0200242
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200243 return nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +0200244}
245
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200246/*! Encode a ASCII characterrs as 7-bit GSM alphabet (TS 03.38)
Harald Welte96e2a002017-06-12 21:44:18 +0200247 *
248 * This function converts a zero-terminated input string \a data from
249 * ASCII into octet-aligned 7-bit GSM characters. No packing is
250 * performed.
251 *
252 * \param[out] result caller-allocated output buffer
253 * \param[in] data input data, ASCII
254 * \returns number of octets used in \a result */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200255int gsm_septet_encode(uint8_t *result, const char *data)
Nico Golde28de0532010-07-09 17:19:12 +0200256{
257 int i, y = 0;
258 uint8_t ch;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200259 for (i = 0; i < strlen(data); i++) {
Nico Golde28de0532010-07-09 17:19:12 +0200260 ch = data[i];
261 switch(ch){
262 /* fall-through for extension characters */
263 case 0x0c:
264 case 0x5e:
265 case 0x7b:
266 case 0x7d:
267 case 0x5c:
268 case 0x5b:
269 case 0x7e:
270 case 0x5d:
271 case 0x7c:
272 result[y++] = 0x1b;
273 default:
274 result[y] = gsm_7bit_alphabet[ch];
275 break;
276 }
277 y++;
278 }
279
280 return y;
281}
282
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200283/*! GSM Default Alphabet 7bit to octet packing
Harald Welte96e2a002017-06-12 21:44:18 +0200284 * \param[out] result Caller-provided output buffer
285 * \param[in] rdata Input data septets
286 * \param[in] septet_len Length of \a rdata
287 * \param[in] padding padding bits at start
288 * \returns number of bytes used in \a result */
Harald Welteca693882013-03-13 15:10:55 +0100289int gsm_septets2octets(uint8_t *result, const uint8_t *rdata, uint8_t septet_len, uint8_t padding)
290{
Dennis Wehrle291e6132011-07-24 20:14:13 +0200291 int i = 0, z = 0;
Nico Golde28de0532010-07-09 17:19:12 +0200292 uint8_t cb, nb;
293 int shift = 0;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200294 uint8_t *data = calloc(septet_len + 1, sizeof(uint8_t));
Nico Golde28de0532010-07-09 17:19:12 +0200295
Dennis Wehrle291e6132011-07-24 20:14:13 +0200296 if (padding) {
297 shift = 7 - padding;
298 /* the first zero is needed for padding */
299 memcpy(data + 1, rdata, septet_len);
300 septet_len++;
301 } else
302 memcpy(data, rdata, septet_len);
Nico Golde28de0532010-07-09 17:19:12 +0200303
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200304 for (i = 0; i < septet_len; i++) {
Dennis Wehrle291e6132011-07-24 20:14:13 +0200305 if (shift == 7) {
306 /*
307 * special end case with the. This is necessary if the
308 * last septet fits into the previous octet. E.g. 48
309 * non-extension characters:
310 * ....ag ( a = 1100001, g = 1100111)
311 * result[40] = 100001 XX, result[41] = 1100111 1 */
312 if (i + 1 < septet_len) {
313 shift = 0;
314 continue;
315 } else if (i + 1 == septet_len)
316 break;
Nico Golde28de0532010-07-09 17:19:12 +0200317 }
318
Dennis Wehrle291e6132011-07-24 20:14:13 +0200319 cb = (data[i] & 0x7f) >> shift;
320 if (i + 1 < septet_len) {
321 nb = (data[i + 1] & 0x7f) << (7 - shift);
Nico Golde28de0532010-07-09 17:19:12 +0200322 cb = cb | nb;
323 }
324
325 result[z++] = cb;
Nico Golde28de0532010-07-09 17:19:12 +0200326 shift++;
327 }
328
Dennis Wehrle291e6132011-07-24 20:14:13 +0200329 free(data);
330
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200331 return z;
Harald Welteec8b4502010-02-20 20:34:29 +0100332}
333
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200334/*! GSM 7-bit alphabet TS 03.38 6.2.1 Character packing
Harald Welte96e2a002017-06-12 21:44:18 +0200335 * \param[out] result Caller-provided output buffer
336 * \param[in] n Maximum length of \a result in bytes
337 * \param[in] data octet-aligned string
338 * \param[out] octets Number of octets encoded
339 * \returns number of septets encoded */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200340int gsm_7bit_encode_n(uint8_t *result, size_t n, const char *data, int *octets)
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +0200341{
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200342 int y = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200343 int o;
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100344 size_t max_septets = n * 8 / 7;
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200345
Dennis Wehrle291e6132011-07-24 20:14:13 +0200346 /* prepare for the worst case, every character expanding to two bytes */
347 uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
348 y = gsm_septet_encode(rdata, data);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200349
350 if (y > max_septets) {
351 /*
352 * Limit the number of septets to avoid the generation
353 * of more than n octets.
354 */
355 y = max_septets;
356 }
357
358 o = gsm_septets2octets(result, rdata, y, 0);
359
360 if (octets)
361 *octets = o;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200362
363 free(rdata);
364
365 /*
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200366 * We don't care about the number of octets, because they are not
Dennis Wehrle291e6132011-07-24 20:14:13 +0200367 * unique. E.g.:
368 * 1.) 46 non-extension characters + 1 extension character
369 * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets
370 * 2.) 47 non-extension characters
371 * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets
372 * 3.) 48 non-extension characters
373 * => (48 * 7 bit) / 8 bit = 42 octects
374 */
375 return y;
376}
377
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200378/*! Encode according to GSM 7-bit alphabet (TS 03.38 6.2.1) for USSD
Harald Welte96e2a002017-06-12 21:44:18 +0200379 * \param[out] result Caller-provided output buffer
380 * \param[in] n Maximum length of \a result in bytes
381 * \param[in] data octet-aligned string
382 * \param[out] octets Number of octets encoded
383 * \returns number of septets encoded */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200384int gsm_7bit_encode_n_ussd(uint8_t *result, size_t n, const char *data, int *octets)
385{
386 int y;
387
388 y = gsm_7bit_encode_n(result, n, data, octets);
389 /* if last octet contains only one bit, add <CR> */
390 if (((y * 7) & 7) == 1)
391 result[(*octets) - 1] |= ('\r' << 1);
392 /* if last character is <CR> and completely fills last octet, add
393 * another <CR>. */
394 if (y && ((y * 7) & 7) == 0 && (result[(*octets) - 1] >> 1) == '\r' && *octets < n - 1) {
395 result[(*octets)++] = '\r';
396 y++;
397 }
398
399 return y;
400}
401
Max4b2b0cc2017-07-10 14:32:48 +0200402/*! Generate random identifier
403 * We use /dev/urandom (default when GRND_RANDOM flag is not set).
404 * Both /dev/(u)random numbers are coming from the same CSPRNG anyway (at least on GNU/Linux >= 4.8).
405 * See also RFC4086.
406 * \param[out] out Buffer to be filled with random data
407 * \param[in] len Number of random bytes required
408 * \returns 0 on success, or a negative error code on error.
409 */
410int osmo_get_rand_id(uint8_t *out, size_t len)
411{
412 int rc;
413
414 /* this function is intended for generating short identifiers only, not arbitrary-length random data */
415 if (len > OSMO_MAX_RAND_ID_LEN)
416 return -E2BIG;
417
418#if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25)
419 rc = getrandom(out, len, GRND_NONBLOCK);
420#elif HAVE_DECL_SYS_GETRANDOM
421#pragma message ("Using direct syscall access for getrandom(): consider upgrading to glibc >= 2.25")
422 /* FIXME: this can be removed once we bump glibc requirements to 2.25: */
423 rc = syscall(SYS_getrandom, out, len, GRND_NONBLOCK);
424#else
425#pragma message ("Secure random unavailable: calls to osmo_get_rand_id() will always fail!")
426 return -ENOTSUP;
427#endif
428 /* getrandom() failed entirely: */
429 if (rc < 0)
430 return -errno;
431
432 /* getrandom() failed partially due to signal interruption:
433 this should never happen (according to getrandom(2)) as long as OSMO_MAX_RAND_ID_LEN < 256
434 because we do not set GRND_RANDOM but it's better to be paranoid and check anyway */
435 if (rc != len)
436 return -EAGAIN;
437
438 return 0;
439}
440
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200441/*! Build the RSL uplink measurement IE (3GPP TS 08.58 § 9.3.25)
Max764b0222016-05-11 17:33:17 +0200442 * \param[in] mru Unidirectional measurement report structure
443 * \param[in] dtxd_used Indicates if DTXd was used during measurement report
444 * period
445 * \param[out] buf Pre-allocated bufer for storing IE
446 * \returns Number of bytes filled in buf
447 */
448size_t gsm0858_rsl_ul_meas_enc(struct gsm_meas_rep_unidir *mru, bool dtxd_used,
449 uint8_t *buf)
450{
451 buf[0] = dtxd_used ? (1 << 6) : 0;
452 buf[0] |= (mru->full.rx_lev & 0x3f);
453 buf[1] = (mru->sub.rx_lev & 0x3f);
454 buf[2] = ((mru->full.rx_qual & 7) << 3) | (mru->sub.rx_qual & 7);
455
456 return 3;
457}
458
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200459/*! Convert power class to dBm according to GSM TS 05.05
Harald Welte96e2a002017-06-12 21:44:18 +0200460 * \param[in] band GSM frequency band
461 * \param[in] class GSM power class
462 * \returns maximum transmit power of power class in dBm */
Andreas Eversberg2a68c7c2011-06-26 11:41:48 +0200463unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class)
464{
465 switch (band) {
466 case GSM_BAND_450:
467 case GSM_BAND_480:
468 case GSM_BAND_750:
469 case GSM_BAND_900:
470 case GSM_BAND_810:
471 case GSM_BAND_850:
472 if (class == 1)
473 return 43; /* 20W */
474 if (class == 2)
475 return 39; /* 8W */
476 if (class == 3)
477 return 37; /* 5W */
478 if (class == 4)
479 return 33; /* 2W */
480 if (class == 5)
481 return 29; /* 0.8W */
482 break;
483 case GSM_BAND_1800:
484 if (class == 1)
485 return 30; /* 1W */
486 if (class == 2)
487 return 24; /* 0.25W */
488 if (class == 3)
489 return 36; /* 4W */
490 break;
491 case GSM_BAND_1900:
492 if (class == 1)
493 return 30; /* 1W */
494 if (class == 2)
495 return 24; /* 0.25W */
496 if (class == 3)
497 return 33; /* 2W */
498 break;
499 }
500 return -EINVAL;
501}
502
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200503/*! determine power control level for given dBm value, as indicated
Harald Welte96e2a002017-06-12 21:44:18 +0200504 * by the tables in chapter 4.1.1 of GSM TS 05.05
505 * \param[in] GSM frequency band
506 * \param[in] dbm RF power value in dBm
507 * \returns TS 05.05 power control level */
Harald Welteec8b4502010-02-20 20:34:29 +0100508int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
509{
510 switch (band) {
511 case GSM_BAND_450:
512 case GSM_BAND_480:
513 case GSM_BAND_750:
514 case GSM_BAND_900:
515 case GSM_BAND_810:
516 case GSM_BAND_850:
517 if (dbm >= 39)
518 return 0;
519 else if (dbm < 5)
520 return 19;
521 else {
522 /* we are guaranteed to have (5 <= dbm < 39) */
523 return 2 + ((39 - dbm) / 2);
524 }
525 break;
526 case GSM_BAND_1800:
527 if (dbm >= 36)
528 return 29;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200529 else if (dbm >= 34)
Harald Welteec8b4502010-02-20 20:34:29 +0100530 return 30;
531 else if (dbm >= 32)
532 return 31;
533 else if (dbm == 31)
534 return 0;
535 else {
536 /* we are guaranteed to have (0 <= dbm < 31) */
537 return (30 - dbm) / 2;
538 }
539 break;
540 case GSM_BAND_1900:
541 if (dbm >= 33)
542 return 30;
543 else if (dbm >= 32)
544 return 31;
545 else if (dbm == 31)
546 return 0;
547 else {
548 /* we are guaranteed to have (0 <= dbm < 31) */
549 return (30 - dbm) / 2;
550 }
551 break;
552 }
553 return -EINVAL;
554}
555
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200556/*! Convert TS 05.05 power level to absolute dBm value
Harald Welte96e2a002017-06-12 21:44:18 +0200557 * \param[in] band GSM frequency band
558 * \param[in] lvl TS 05.05 power control level
559 * \returns RF power level in dBm */
Harald Welteec8b4502010-02-20 20:34:29 +0100560int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
561{
562 lvl &= 0x1f;
563
564 switch (band) {
565 case GSM_BAND_450:
566 case GSM_BAND_480:
567 case GSM_BAND_750:
568 case GSM_BAND_900:
569 case GSM_BAND_810:
570 case GSM_BAND_850:
571 if (lvl < 2)
572 return 39;
573 else if (lvl < 20)
574 return 39 - ((lvl - 2) * 2) ;
575 else
576 return 5;
577 break;
578 case GSM_BAND_1800:
579 if (lvl < 16)
580 return 30 - (lvl * 2);
581 else if (lvl < 29)
582 return 0;
583 else
584 return 36 - ((lvl - 29) * 2);
585 break;
586 case GSM_BAND_1900:
587 if (lvl < 16)
588 return 30 - (lvl * 2);
589 else if (lvl < 30)
590 return -EINVAL;
591 else
592 return 33 - (lvl - 30);
593 break;
594 }
595 return -EINVAL;
596}
597
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200598/*! Convert TS 05.08 RxLev to dBm (TS 05.08 Chapter 8.1.4)
Harald Welte96e2a002017-06-12 21:44:18 +0200599 * \param[in] rxlev TS 05.08 RxLev value
600 * \returns Received RF power in dBm */
Harald Welteec8b4502010-02-20 20:34:29 +0100601int rxlev2dbm(uint8_t rxlev)
602{
603 if (rxlev > 63)
604 rxlev = 63;
605
606 return -110 + rxlev;
607}
608
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200609/*! 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 +0200610 * \param[in] dbm RF signal level in dBm
611 * \returns TS 05.08 RxLev value */
Harald Welteec8b4502010-02-20 20:34:29 +0100612uint8_t dbm2rxlev(int dbm)
613{
614 int rxlev = dbm + 110;
615
616 if (rxlev > 63)
617 rxlev = 63;
618 else if (rxlev < 0)
619 rxlev = 0;
620
621 return rxlev;
622}
623
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200624/*! Return string name of a given GSM Band */
Harald Weltecbc80622010-03-22 08:28:44 +0800625const char *gsm_band_name(enum gsm_band band)
Harald Welteaebe08c2010-03-04 10:39:17 +0100626{
627 switch (band) {
628 case GSM_BAND_450:
629 return "GSM450";
630 case GSM_BAND_480:
Sylvain Munaute10ae5b2010-07-04 11:41:36 +0200631 return "GSM480";
Harald Welteaebe08c2010-03-04 10:39:17 +0100632 case GSM_BAND_750:
633 return "GSM750";
634 case GSM_BAND_810:
635 return "GSM810";
636 case GSM_BAND_850:
637 return "GSM850";
638 case GSM_BAND_900:
639 return "GSM900";
640 case GSM_BAND_1800:
641 return "DCS1800";
642 case GSM_BAND_1900:
643 return "PCS1900";
644 }
645 return "invalid";
646}
647
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200648/*! Parse string name of a GSM band */
Harald Welteaebe08c2010-03-04 10:39:17 +0100649enum gsm_band gsm_band_parse(const char* mhz)
650{
Pau Espin Pedrol399a6f02017-06-18 14:07:37 +0200651 while (*mhz && !isdigit((unsigned char)*mhz))
Harald Welteaebe08c2010-03-04 10:39:17 +0100652 mhz++;
653
654 if (*mhz == '\0')
655 return -EINVAL;
656
Harald Welted3ff15f2010-03-07 18:23:47 +0100657 switch (strtol(mhz, NULL, 10)) {
Harald Welteaebe08c2010-03-04 10:39:17 +0100658 case 450:
659 return GSM_BAND_450;
660 case 480:
661 return GSM_BAND_480;
662 case 750:
663 return GSM_BAND_750;
664 case 810:
665 return GSM_BAND_810;
666 case 850:
667 return GSM_BAND_850;
668 case 900:
669 return GSM_BAND_900;
670 case 1800:
671 return GSM_BAND_1800;
672 case 1900:
673 return GSM_BAND_1900;
674 default:
675 return -EINVAL;
676 }
677}
678
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200679/*! Resolve GSM band from ARFCN
Harald Welte96e2a002017-06-12 21:44:18 +0200680 * In Osmocom, we use the highest bit of the \a arfcn to indicate PCS
681 * \param[in] arfcn Osmocom ARFCN, highest bit determines PCS mode
682 * \returns GSM Band */
Harald Welte622b7182010-03-07 17:50:21 +0100683enum gsm_band gsm_arfcn2band(uint16_t arfcn)
684{
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100685 int is_pcs = arfcn & ARFCN_PCS;
686
687 arfcn &= ~ARFCN_FLAG_MASK;
688
689 if (is_pcs)
Harald Welte622b7182010-03-07 17:50:21 +0100690 return GSM_BAND_1900;
691 else if (arfcn <= 124)
692 return GSM_BAND_900;
693 else if (arfcn >= 955 && arfcn <= 1023)
694 return GSM_BAND_900;
695 else if (arfcn >= 128 && arfcn <= 251)
696 return GSM_BAND_850;
697 else if (arfcn >= 512 && arfcn <= 885)
698 return GSM_BAND_1800;
699 else if (arfcn >= 259 && arfcn <= 293)
700 return GSM_BAND_450;
701 else if (arfcn >= 306 && arfcn <= 340)
702 return GSM_BAND_480;
703 else if (arfcn >= 350 && arfcn <= 425)
704 return GSM_BAND_810;
705 else if (arfcn >= 438 && arfcn <= 511)
706 return GSM_BAND_750;
707 else
708 return GSM_BAND_1800;
709}
710
Sylvain Munaut55720312012-12-11 23:44:41 +0100711struct gsm_freq_range {
712 uint16_t arfcn_first;
713 uint16_t arfcn_last;
714 uint16_t freq_ul_first;
715 uint16_t freq_dl_offset;
716 uint16_t flags;
717};
718
719static struct gsm_freq_range gsm_ranges[] = {
720 { 512, 810, 18502, 800, ARFCN_PCS }, /* PCS 1900 */
721 { 0, 124, 8900, 450, 0 }, /* P-GSM + E-GSM ARFCN 0 */
722 { 955, 1023, 8762, 450, 0 }, /* E-GSM + R-GSM */
723 { 128, 251, 8242, 450, 0 }, /* GSM 850 */
724 { 512, 885, 17102, 950, 0 }, /* DCS 1800 */
725 { 259, 293, 4506, 100, 0 }, /* GSM 450 */
726 { 306, 340, 4790, 100, 0 }, /* GSM 480 */
727 { 350, 425, 8060, 450, 0 }, /* GSM 810 */
728 { 438, 511, 7472, 300, 0 }, /* GSM 750 */
729 { /* Guard */ }
730};
731
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200732/*! Convert an ARFCN to the frequency in MHz * 10
Harald Welte96e2a002017-06-12 21:44:18 +0200733 * \param[in] arfcn GSM ARFCN to convert
734 * \param[in] uplink Uplink (1) or Downlink (0) frequency
735 * \returns Frequency in units of 1/10ths of MHz (100kHz) */
Harald Welte622b7182010-03-07 17:50:21 +0100736uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
737{
Sylvain Munaut55720312012-12-11 23:44:41 +0100738 struct gsm_freq_range *r;
739 uint16_t flags = arfcn & ARFCN_FLAG_MASK;
740 uint16_t freq10_ul = 0xffff;
741 uint16_t freq10_dl = 0xffff;
Harald Welte622b7182010-03-07 17:50:21 +0100742
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100743 arfcn &= ~ARFCN_FLAG_MASK;
744
Sylvain Munaut55720312012-12-11 23:44:41 +0100745 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
746 if ((flags == r->flags) &&
747 (arfcn >= r->arfcn_first) &&
748 (arfcn <= r->arfcn_last))
749 {
750 freq10_ul = r->freq_ul_first + 2 * (arfcn - r->arfcn_first);
751 freq10_dl = freq10_ul + r->freq_dl_offset;
752 break;
753 }
754 }
755
756 return uplink ? freq10_ul : freq10_dl;
757}
758
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200759/*! Convert a Frequency in MHz * 10 to ARFCN
Harald Welte96e2a002017-06-12 21:44:18 +0200760 * \param[in] freq10 Frequency in units of 1/10ths of MHz (100kHz)
761 * \param[in] uplink Frequency is Uplink (1) or Downlink (0)
762 * \returns ARFCN in case of success; 0xffff on error */
Sylvain Munaut55720312012-12-11 23:44:41 +0100763uint16_t gsm_freq102arfcn(uint16_t freq10, int uplink)
764{
765 struct gsm_freq_range *r;
766 uint16_t freq10_lo, freq10_hi;
767 uint16_t arfcn = 0xffff;
768
769 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
770 /* Generate frequency limits */
771 freq10_lo = r->freq_ul_first;
772 freq10_hi = freq10_lo + 2 * (r->arfcn_last - r->arfcn_first);
773 if (!uplink) {
774 freq10_lo += r->freq_dl_offset;
775 freq10_hi += r->freq_dl_offset;
776 }
777
778 /* Check if this fits */
779 if (freq10 >= freq10_lo && freq10 <= freq10_hi) {
780 arfcn = r->arfcn_first + ((freq10 - freq10_lo) >> 1);
781 arfcn |= r->flags;
782 break;
783 }
784 }
Harald Welte622b7182010-03-07 17:50:21 +0100785
786 if (uplink)
Sylvain Munaut55720312012-12-11 23:44:41 +0100787 arfcn |= ARFCN_UPLINK;
788
789 return arfcn;
Harald Welte622b7182010-03-07 17:50:21 +0100790}
791
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200792/*! Parse GSM Frame Number into struct \ref gsm_time
Harald Welte96e2a002017-06-12 21:44:18 +0200793 * \param[out] time Caller-provided memory for \ref gsm_time
794 * \param[in] fn GSM Frame Number */
Harald Welte622b7182010-03-07 17:50:21 +0100795void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
796{
797 time->fn = fn;
798 time->t1 = time->fn / (26*51);
799 time->t2 = time->fn % 26;
800 time->t3 = time->fn % 51;
801 time->tc = (time->fn / 51) % 8;
802}
803
Philipp Maierb808da42017-06-26 10:50:28 +0200804/*! Parse GSM Frame Number into printable string
805 * \param[in] fn GSM Frame Number
806 * \returns pointer to printable string */
807char *gsm_fn_as_gsmtime_str(uint32_t fn)
808{
809 struct gsm_time time;
810
811 gsm_fn2gsmtime(&time, fn);
812 return osmo_dump_gsmtime(&time);
813}
814
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200815/*! Encode decoded \ref gsm_time to Frame Number
Harald Welte96e2a002017-06-12 21:44:18 +0200816 * \param[in] time GSM Time in decoded structure
817 * \returns GSM Frame Number */
Harald Welte622b7182010-03-07 17:50:21 +0100818uint32_t gsm_gsmtime2fn(struct gsm_time *time)
819{
820 /* TS 05.02 Chapter 4.3.3 TDMA frame number */
821 return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
822}
Harald Weltea1c4f762010-05-01 11:59:42 +0200823
Pau Espin Pedrol363130f2017-07-03 10:42:42 +0200824char *osmo_dump_gsmtime(const struct gsm_time *tm)
825{
826 static char buf[64];
827
828 snprintf(buf, sizeof(buf), "%06"PRIu32"/%02"PRIu16"/%02"PRIu8"/%02"PRIu8"/%02"PRIu8,
829 tm->fn, tm->t1, tm->t2, tm->t3, (uint8_t)tm->fn%52);
830 buf[sizeof(buf)-1] = '\0';
831 return buf;
832}
833
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200834/*! append range1024 encoded data to bit vector
Harald Welte96e2a002017-06-12 21:44:18 +0200835 * \param[out] bv Caller-provided output bit-vector
836 * \param[in] r Input Range1024 sructure */
Max8a5346b2016-04-22 19:28:09 +0200837void bitvec_add_range1024(struct bitvec *bv, const struct gsm48_range_1024 *r)
838{
839 bitvec_set_uint(bv, r->w1_hi, 2);
840 bitvec_set_uint(bv, r->w1_lo, 8);
841 bitvec_set_uint(bv, r->w2_hi, 8);
842 bitvec_set_uint(bv, r->w2_lo, 1);
843 bitvec_set_uint(bv, r->w3_hi, 7);
844 bitvec_set_uint(bv, r->w3_lo, 2);
845 bitvec_set_uint(bv, r->w4_hi, 6);
846 bitvec_set_uint(bv, r->w4_lo, 2);
847 bitvec_set_uint(bv, r->w5_hi, 6);
848 bitvec_set_uint(bv, r->w5_lo, 2);
849 bitvec_set_uint(bv, r->w6_hi, 6);
850 bitvec_set_uint(bv, r->w6_lo, 2);
851 bitvec_set_uint(bv, r->w7_hi, 6);
852 bitvec_set_uint(bv, r->w7_lo, 2);
853 bitvec_set_uint(bv, r->w8_hi, 6);
854 bitvec_set_uint(bv, r->w8_lo, 1);
855 bitvec_set_uint(bv, r->w9, 7);
856 bitvec_set_uint(bv, r->w10, 7);
857 bitvec_set_uint(bv, r->w11_hi, 1);
858 bitvec_set_uint(bv, r->w11_lo, 6);
859 bitvec_set_uint(bv, r->w12_hi, 2);
860 bitvec_set_uint(bv, r->w12_lo, 5);
861 bitvec_set_uint(bv, r->w13_hi, 3);
862 bitvec_set_uint(bv, r->w13_lo, 4);
863 bitvec_set_uint(bv, r->w14_hi, 4);
864 bitvec_set_uint(bv, r->w14_lo, 3);
865 bitvec_set_uint(bv, r->w15_hi, 5);
866 bitvec_set_uint(bv, r->w15_lo, 2);
867 bitvec_set_uint(bv, r->w16, 6);
868}
869
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200870/*! Determine GPRS TLLI Type (TS 23.003 Chapter 2.6) */
Harald Weltea1c4f762010-05-01 11:59:42 +0200871int gprs_tlli_type(uint32_t tlli)
872{
873 if ((tlli & 0xc0000000) == 0xc0000000)
874 return TLLI_LOCAL;
875 else if ((tlli & 0xc0000000) == 0x80000000)
876 return TLLI_FOREIGN;
877 else if ((tlli & 0xf8000000) == 0x78000000)
878 return TLLI_RANDOM;
879 else if ((tlli & 0xf8000000) == 0x70000000)
880 return TLLI_AUXILIARY;
Harald Welte1f6aad12015-08-15 19:51:45 +0200881 else if ((tlli & 0xf0000000) == 0x00000000)
882 return TLLI_G_RNTI;
883 else if ((tlli & 0xf0000000) == 0x10000000)
884 return TLLI_RAND_G_RNTI;
Harald Weltea1c4f762010-05-01 11:59:42 +0200885
886 return TLLI_RESERVED;
887}
Harald Weltec2263172010-06-01 10:47:07 +0200888
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200889/*! Determine TLLI from P-TMSI
Harald Welte96e2a002017-06-12 21:44:18 +0200890 * \param[in] p_tmsi P-TMSI
891 * \param[in] type TLLI Type we want to derive from \a p_tmsi
892 * \returns TLLI of given type */
Harald Weltec2263172010-06-01 10:47:07 +0200893uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
894{
895 uint32_t tlli;
896 switch (type) {
897 case TLLI_LOCAL:
898 tlli = p_tmsi | 0xc0000000;
899 break;
900 case TLLI_FOREIGN:
901 tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
902 break;
903 default:
904 tlli = 0;
905 break;
906 }
907 return tlli;
908}
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200909
910/* Wrappers for deprecated functions: */
911
912int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l)
913{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100914 gsm_7bit_decode_n(text, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
915 user_data, septet_l);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200916
917 /* Mimic the original behaviour. */
918 return septet_l;
919}
920
921int gsm_7bit_decode_ussd(char *text, const uint8_t *user_data, uint8_t length)
922{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100923 return gsm_7bit_decode_n_ussd(text, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
924 user_data, length);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200925}
926
927int gsm_7bit_encode(uint8_t *result, const char *data)
928{
929 int out;
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100930 return gsm_7bit_encode_n(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
931 data, &out);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200932}
933
934int gsm_7bit_encode_ussd(uint8_t *result, const char *data, int *octets)
935{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100936 return gsm_7bit_encode_n_ussd(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
937 data, octets);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200938}
939
940int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets)
941{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100942 return gsm_7bit_encode_n(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
943 data, octets);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200944}