blob: f572c64355ef034a48223e87ff59f9fd584256be [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>
104#endif
105
Holger Hans Peter Freytherdd02a472010-07-23 16:35:00 +0800106/* ETSI GSM 03.38 6.2.1 and 6.2.1.1 default alphabet
107 * Greek symbols at hex positions 0x10 and 0x12-0x1a
108 * left out as they can't be handled with a char and
109 * since most phones don't display or write these
110 * characters this would only needlessly make the code
Jacob Erlbeck18109252013-08-12 17:07:54 +0200111 * more complex.
112 *
113 * Note that this table contains the latin1->7bit mapping _and_ has
114 * been merged with the reverse mapping (7bit->latin1) for the
115 * extended characters at offset 0x7f.
116 */
Holger Hans Peter Freytherdd02a472010-07-23 16:35:00 +0800117static unsigned char gsm_7bit_alphabet[] = {
118 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0x0d, 0xff,
119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
120 0xff, 0xff, 0x20, 0x21, 0x22, 0x23, 0x02, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
121 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
122 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
123 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
124 0x5a, 0x3c, 0x2f, 0x3e, 0x14, 0x11, 0xff, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
125 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
126 0x78, 0x79, 0x7a, 0x28, 0x40, 0x29, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
127 0xff, 0xff, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff,
128 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0xff, 0x01, 0xff,
129 0x03, 0xff, 0x7b, 0x7d, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff,
130 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5b, 0x7e, 0x5d, 0xff, 0x7c, 0xff, 0xff, 0xff,
131 0xff, 0x5b, 0x0e, 0x1c, 0x09, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5d,
132 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0x0b, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff, 0x1e, 0x7f,
133 0xff, 0xff, 0xff, 0x7b, 0x0f, 0x1d, 0xff, 0x04, 0x05, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff,
134 0xff, 0x7d, 0x08, 0xff, 0xff, 0xff, 0x7c, 0xff, 0x0c, 0x06, 0xff, 0xff, 0x7e, 0xff, 0xff
135};
136
Nico Golde28de0532010-07-09 17:19:12 +0200137/* GSM 03.38 6.2.1 Character lookup for decoding */
138static int gsm_septet_lookup(uint8_t ch)
139{
140 int i = 0;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200141 for (; i < sizeof(gsm_7bit_alphabet); i++) {
142 if (gsm_7bit_alphabet[i] == ch)
Nico Golde28de0532010-07-09 17:19:12 +0200143 return i;
144 }
145 return -1;
146}
147
Harald Welte96e2a002017-06-12 21:44:18 +0200148/*! \brife Compute number of octets from number of septets,
149 * for instance: 47 septets needs 41,125 = 42 octets
150 * \param[in sept_len Number of Septets
151 * \returns Number of octets required */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200152uint8_t gsm_get_octet_len(const uint8_t sept_len){
153 int octet_len = (sept_len * 7) / 8;
154 if ((sept_len * 7) % 8 != 0)
155 octet_len++;
156
157 return octet_len;
158}
159
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200160/*! TS 03.38 7-bit Character unpacking (6.2.1)
Harald Welte96e2a002017-06-12 21:44:18 +0200161 * \param[out] text Caller-provided output text buffer
162 * \param[in] n Length of \a text
163 * \param[in] user_data Input Data (septets)
164 * \param[in] septet_l Number of septets in \a user_data
165 * \param[in] ud_hdr_ind User Data Header present in data
166 * \returns number of bytes written to \a text */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200167int 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 +0100168{
Maxcf37c4c2016-01-21 16:52:40 +0100169 unsigned shift = 0;
170 uint8_t c7, c8, next_is_ext = 0, lu, ru;
171 const uint8_t maxlen = gsm_get_octet_len(septet_l);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200172 const char *text_buf_begin = text;
173 const char *text_buf_end = text + n;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200174
175 OSMO_ASSERT (n > 0);
Harald Welteec8b4502010-02-20 20:34:29 +0100176
Dennis Wehrle291e6132011-07-24 20:14:13 +0200177 /* skip the user data header */
178 if (ud_hdr_ind) {
179 /* get user data header length + 1 (for the 'user data header length'-field) */
180 shift = ((user_data[0] + 1) * 8) / 7;
181 if ((((user_data[0] + 1) * 8) % 7) != 0)
182 shift++;
183 septet_l = septet_l - shift;
184 }
185
Maxcf37c4c2016-01-21 16:52:40 +0100186 unsigned i, l, r;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200187 for (i = 0; i < septet_l && text != text_buf_end - 1; i++) {
Maxcf37c4c2016-01-21 16:52:40 +0100188
189 l = ((i + shift) * 7 + 7) >> 3;
190 r = ((i + shift) * 7) >> 3;
191
192 /* the left side index is always >= right side index
193 sometimes it even gets beyond array boundary
194 check for that explicitly and force 0 instead
195 */
196 if (l >= maxlen)
197 lu = 0;
198 else
199 lu = user_data[l] << (7 - (((i + shift) * 7 + 7) & 7));
200
201 ru = user_data[r] >> (((i + shift) * 7) & 7);
202
203 c7 = (lu | ru) & 0x7f;
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200204
Harald Weltebe55a8b2012-09-20 10:00:25 +0200205 if (next_is_ext) {
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200206 /* this is an extension character */
Nico Goldec56a56d2012-09-18 14:29:40 +0200207 next_is_ext = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200208 c8 = gsm_7bit_alphabet[0x7f + c7];
209 } else if (c7 == 0x1b && i + 1 < septet_l) {
210 next_is_ext = 1;
Nico Golde5b67a042012-09-20 16:56:23 +0200211 continue;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200212 } else {
213 c8 = gsm_septet_lookup(c7);
Nico Golde5b67a042012-09-20 16:56:23 +0200214 }
215
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200216 *(text++) = c8;
Harald Welteec8b4502010-02-20 20:34:29 +0100217 }
218
Nico Golde28de0532010-07-09 17:19:12 +0200219 *text = '\0';
Nico Golde28de0532010-07-09 17:19:12 +0200220
Maxcf37c4c2016-01-21 16:52:40 +0100221 return text - text_buf_begin;
Nico Golde28de0532010-07-09 17:19:12 +0200222}
223
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200224/*! Decode 7bit GSM Alphabet */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200225int 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 +0200226{
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200227 return gsm_7bit_decode_n_hdr(text, n, user_data, septet_l, 0);
Dennis Wehrle291e6132011-07-24 20:14:13 +0200228}
229
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200230/*! Decode 7bit GSM Alphabet (USSD) */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200231int 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 +0200232{
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200233 int nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +0200234
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200235 nchars = gsm_7bit_decode_n_hdr(text, n, user_data, length, 0);
Andreas Eversberg95975552013-08-08 12:38:53 +0200236 /* remove last <CR>, if it fits up to the end of last octet */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200237 if (nchars && (user_data[gsm_get_octet_len(length) - 1] >> 1) == '\r')
238 text[--nchars] = '\0';
Andreas Eversberg95975552013-08-08 12:38:53 +0200239
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200240 return nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +0200241}
242
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200243/*! Encode a ASCII characterrs as 7-bit GSM alphabet (TS 03.38)
Harald Welte96e2a002017-06-12 21:44:18 +0200244 *
245 * This function converts a zero-terminated input string \a data from
246 * ASCII into octet-aligned 7-bit GSM characters. No packing is
247 * performed.
248 *
249 * \param[out] result caller-allocated output buffer
250 * \param[in] data input data, ASCII
251 * \returns number of octets used in \a result */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200252int gsm_septet_encode(uint8_t *result, const char *data)
Nico Golde28de0532010-07-09 17:19:12 +0200253{
254 int i, y = 0;
255 uint8_t ch;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200256 for (i = 0; i < strlen(data); i++) {
Nico Golde28de0532010-07-09 17:19:12 +0200257 ch = data[i];
258 switch(ch){
259 /* fall-through for extension characters */
260 case 0x0c:
261 case 0x5e:
262 case 0x7b:
263 case 0x7d:
264 case 0x5c:
265 case 0x5b:
266 case 0x7e:
267 case 0x5d:
268 case 0x7c:
269 result[y++] = 0x1b;
270 default:
271 result[y] = gsm_7bit_alphabet[ch];
272 break;
273 }
274 y++;
275 }
276
277 return y;
278}
279
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200280/*! GSM Default Alphabet 7bit to octet packing
Harald Welte96e2a002017-06-12 21:44:18 +0200281 * \param[out] result Caller-provided output buffer
282 * \param[in] rdata Input data septets
283 * \param[in] septet_len Length of \a rdata
284 * \param[in] padding padding bits at start
285 * \returns number of bytes used in \a result */
Harald Welteca693882013-03-13 15:10:55 +0100286int gsm_septets2octets(uint8_t *result, const uint8_t *rdata, uint8_t septet_len, uint8_t padding)
287{
Dennis Wehrle291e6132011-07-24 20:14:13 +0200288 int i = 0, z = 0;
Nico Golde28de0532010-07-09 17:19:12 +0200289 uint8_t cb, nb;
290 int shift = 0;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200291 uint8_t *data = calloc(septet_len + 1, sizeof(uint8_t));
Nico Golde28de0532010-07-09 17:19:12 +0200292
Dennis Wehrle291e6132011-07-24 20:14:13 +0200293 if (padding) {
294 shift = 7 - padding;
295 /* the first zero is needed for padding */
296 memcpy(data + 1, rdata, septet_len);
297 septet_len++;
298 } else
299 memcpy(data, rdata, septet_len);
Nico Golde28de0532010-07-09 17:19:12 +0200300
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200301 for (i = 0; i < septet_len; i++) {
Dennis Wehrle291e6132011-07-24 20:14:13 +0200302 if (shift == 7) {
303 /*
304 * special end case with the. This is necessary if the
305 * last septet fits into the previous octet. E.g. 48
306 * non-extension characters:
307 * ....ag ( a = 1100001, g = 1100111)
308 * result[40] = 100001 XX, result[41] = 1100111 1 */
309 if (i + 1 < septet_len) {
310 shift = 0;
311 continue;
312 } else if (i + 1 == septet_len)
313 break;
Nico Golde28de0532010-07-09 17:19:12 +0200314 }
315
Dennis Wehrle291e6132011-07-24 20:14:13 +0200316 cb = (data[i] & 0x7f) >> shift;
317 if (i + 1 < septet_len) {
318 nb = (data[i + 1] & 0x7f) << (7 - shift);
Nico Golde28de0532010-07-09 17:19:12 +0200319 cb = cb | nb;
320 }
321
322 result[z++] = cb;
Nico Golde28de0532010-07-09 17:19:12 +0200323 shift++;
324 }
325
Dennis Wehrle291e6132011-07-24 20:14:13 +0200326 free(data);
327
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200328 return z;
Harald Welteec8b4502010-02-20 20:34:29 +0100329}
330
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200331/*! GSM 7-bit alphabet TS 03.38 6.2.1 Character packing
Harald Welte96e2a002017-06-12 21:44:18 +0200332 * \param[out] result Caller-provided output buffer
333 * \param[in] n Maximum length of \a result in bytes
334 * \param[in] data octet-aligned string
335 * \param[out] octets Number of octets encoded
336 * \returns number of septets encoded */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200337int gsm_7bit_encode_n(uint8_t *result, size_t n, const char *data, int *octets)
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +0200338{
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200339 int y = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200340 int o;
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100341 size_t max_septets = n * 8 / 7;
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200342
Dennis Wehrle291e6132011-07-24 20:14:13 +0200343 /* prepare for the worst case, every character expanding to two bytes */
344 uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
345 y = gsm_septet_encode(rdata, data);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200346
347 if (y > max_septets) {
348 /*
349 * Limit the number of septets to avoid the generation
350 * of more than n octets.
351 */
352 y = max_septets;
353 }
354
355 o = gsm_septets2octets(result, rdata, y, 0);
356
357 if (octets)
358 *octets = o;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200359
360 free(rdata);
361
362 /*
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200363 * We don't care about the number of octets, because they are not
Dennis Wehrle291e6132011-07-24 20:14:13 +0200364 * unique. E.g.:
365 * 1.) 46 non-extension characters + 1 extension character
366 * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets
367 * 2.) 47 non-extension characters
368 * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets
369 * 3.) 48 non-extension characters
370 * => (48 * 7 bit) / 8 bit = 42 octects
371 */
372 return y;
373}
374
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200375/*! Encode according to GSM 7-bit alphabet (TS 03.38 6.2.1) for USSD
Harald Welte96e2a002017-06-12 21:44:18 +0200376 * \param[out] result Caller-provided output buffer
377 * \param[in] n Maximum length of \a result in bytes
378 * \param[in] data octet-aligned string
379 * \param[out] octets Number of octets encoded
380 * \returns number of septets encoded */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200381int gsm_7bit_encode_n_ussd(uint8_t *result, size_t n, const char *data, int *octets)
382{
383 int y;
384
385 y = gsm_7bit_encode_n(result, n, data, octets);
386 /* if last octet contains only one bit, add <CR> */
387 if (((y * 7) & 7) == 1)
388 result[(*octets) - 1] |= ('\r' << 1);
389 /* if last character is <CR> and completely fills last octet, add
390 * another <CR>. */
391 if (y && ((y * 7) & 7) == 0 && (result[(*octets) - 1] >> 1) == '\r' && *octets < n - 1) {
392 result[(*octets)++] = '\r';
393 y++;
394 }
395
396 return y;
397}
398
Max4b2b0cc2017-07-10 14:32:48 +0200399/*! Generate random identifier
400 * We use /dev/urandom (default when GRND_RANDOM flag is not set).
401 * Both /dev/(u)random numbers are coming from the same CSPRNG anyway (at least on GNU/Linux >= 4.8).
402 * See also RFC4086.
403 * \param[out] out Buffer to be filled with random data
404 * \param[in] len Number of random bytes required
405 * \returns 0 on success, or a negative error code on error.
406 */
407int osmo_get_rand_id(uint8_t *out, size_t len)
408{
409 int rc;
410
411 /* this function is intended for generating short identifiers only, not arbitrary-length random data */
412 if (len > OSMO_MAX_RAND_ID_LEN)
413 return -E2BIG;
414
415#if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25)
416 rc = getrandom(out, len, GRND_NONBLOCK);
417#elif HAVE_DECL_SYS_GETRANDOM
418#pragma message ("Using direct syscall access for getrandom(): consider upgrading to glibc >= 2.25")
419 /* FIXME: this can be removed once we bump glibc requirements to 2.25: */
420 rc = syscall(SYS_getrandom, out, len, GRND_NONBLOCK);
421#else
422#pragma message ("Secure random unavailable: calls to osmo_get_rand_id() will always fail!")
423 return -ENOTSUP;
424#endif
425 /* getrandom() failed entirely: */
426 if (rc < 0)
427 return -errno;
428
429 /* getrandom() failed partially due to signal interruption:
430 this should never happen (according to getrandom(2)) as long as OSMO_MAX_RAND_ID_LEN < 256
431 because we do not set GRND_RANDOM but it's better to be paranoid and check anyway */
432 if (rc != len)
433 return -EAGAIN;
434
435 return 0;
436}
437
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200438/*! Build the RSL uplink measurement IE (3GPP TS 08.58 § 9.3.25)
Max764b0222016-05-11 17:33:17 +0200439 * \param[in] mru Unidirectional measurement report structure
440 * \param[in] dtxd_used Indicates if DTXd was used during measurement report
441 * period
442 * \param[out] buf Pre-allocated bufer for storing IE
443 * \returns Number of bytes filled in buf
444 */
445size_t gsm0858_rsl_ul_meas_enc(struct gsm_meas_rep_unidir *mru, bool dtxd_used,
446 uint8_t *buf)
447{
448 buf[0] = dtxd_used ? (1 << 6) : 0;
449 buf[0] |= (mru->full.rx_lev & 0x3f);
450 buf[1] = (mru->sub.rx_lev & 0x3f);
451 buf[2] = ((mru->full.rx_qual & 7) << 3) | (mru->sub.rx_qual & 7);
452
453 return 3;
454}
455
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200456/*! Convert power class to dBm according to GSM TS 05.05
Harald Welte96e2a002017-06-12 21:44:18 +0200457 * \param[in] band GSM frequency band
458 * \param[in] class GSM power class
459 * \returns maximum transmit power of power class in dBm */
Andreas Eversberg2a68c7c2011-06-26 11:41:48 +0200460unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class)
461{
462 switch (band) {
463 case GSM_BAND_450:
464 case GSM_BAND_480:
465 case GSM_BAND_750:
466 case GSM_BAND_900:
467 case GSM_BAND_810:
468 case GSM_BAND_850:
469 if (class == 1)
470 return 43; /* 20W */
471 if (class == 2)
472 return 39; /* 8W */
473 if (class == 3)
474 return 37; /* 5W */
475 if (class == 4)
476 return 33; /* 2W */
477 if (class == 5)
478 return 29; /* 0.8W */
479 break;
480 case GSM_BAND_1800:
481 if (class == 1)
482 return 30; /* 1W */
483 if (class == 2)
484 return 24; /* 0.25W */
485 if (class == 3)
486 return 36; /* 4W */
487 break;
488 case GSM_BAND_1900:
489 if (class == 1)
490 return 30; /* 1W */
491 if (class == 2)
492 return 24; /* 0.25W */
493 if (class == 3)
494 return 33; /* 2W */
495 break;
496 }
497 return -EINVAL;
498}
499
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200500/*! determine power control level for given dBm value, as indicated
Harald Welte96e2a002017-06-12 21:44:18 +0200501 * by the tables in chapter 4.1.1 of GSM TS 05.05
502 * \param[in] GSM frequency band
503 * \param[in] dbm RF power value in dBm
504 * \returns TS 05.05 power control level */
Harald Welteec8b4502010-02-20 20:34:29 +0100505int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
506{
507 switch (band) {
508 case GSM_BAND_450:
509 case GSM_BAND_480:
510 case GSM_BAND_750:
511 case GSM_BAND_900:
512 case GSM_BAND_810:
513 case GSM_BAND_850:
514 if (dbm >= 39)
515 return 0;
516 else if (dbm < 5)
517 return 19;
518 else {
519 /* we are guaranteed to have (5 <= dbm < 39) */
520 return 2 + ((39 - dbm) / 2);
521 }
522 break;
523 case GSM_BAND_1800:
524 if (dbm >= 36)
525 return 29;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200526 else if (dbm >= 34)
Harald Welteec8b4502010-02-20 20:34:29 +0100527 return 30;
528 else if (dbm >= 32)
529 return 31;
530 else if (dbm == 31)
531 return 0;
532 else {
533 /* we are guaranteed to have (0 <= dbm < 31) */
534 return (30 - dbm) / 2;
535 }
536 break;
537 case GSM_BAND_1900:
538 if (dbm >= 33)
539 return 30;
540 else if (dbm >= 32)
541 return 31;
542 else if (dbm == 31)
543 return 0;
544 else {
545 /* we are guaranteed to have (0 <= dbm < 31) */
546 return (30 - dbm) / 2;
547 }
548 break;
549 }
550 return -EINVAL;
551}
552
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200553/*! Convert TS 05.05 power level to absolute dBm value
Harald Welte96e2a002017-06-12 21:44:18 +0200554 * \param[in] band GSM frequency band
555 * \param[in] lvl TS 05.05 power control level
556 * \returns RF power level in dBm */
Harald Welteec8b4502010-02-20 20:34:29 +0100557int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
558{
559 lvl &= 0x1f;
560
561 switch (band) {
562 case GSM_BAND_450:
563 case GSM_BAND_480:
564 case GSM_BAND_750:
565 case GSM_BAND_900:
566 case GSM_BAND_810:
567 case GSM_BAND_850:
568 if (lvl < 2)
569 return 39;
570 else if (lvl < 20)
571 return 39 - ((lvl - 2) * 2) ;
572 else
573 return 5;
574 break;
575 case GSM_BAND_1800:
576 if (lvl < 16)
577 return 30 - (lvl * 2);
578 else if (lvl < 29)
579 return 0;
580 else
581 return 36 - ((lvl - 29) * 2);
582 break;
583 case GSM_BAND_1900:
584 if (lvl < 16)
585 return 30 - (lvl * 2);
586 else if (lvl < 30)
587 return -EINVAL;
588 else
589 return 33 - (lvl - 30);
590 break;
591 }
592 return -EINVAL;
593}
594
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200595/*! Convert TS 05.08 RxLev to dBm (TS 05.08 Chapter 8.1.4)
Harald Welte96e2a002017-06-12 21:44:18 +0200596 * \param[in] rxlev TS 05.08 RxLev value
597 * \returns Received RF power in dBm */
Harald Welteec8b4502010-02-20 20:34:29 +0100598int rxlev2dbm(uint8_t rxlev)
599{
600 if (rxlev > 63)
601 rxlev = 63;
602
603 return -110 + rxlev;
604}
605
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200606/*! 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 +0200607 * \param[in] dbm RF signal level in dBm
608 * \returns TS 05.08 RxLev value */
Harald Welteec8b4502010-02-20 20:34:29 +0100609uint8_t dbm2rxlev(int dbm)
610{
611 int rxlev = dbm + 110;
612
613 if (rxlev > 63)
614 rxlev = 63;
615 else if (rxlev < 0)
616 rxlev = 0;
617
618 return rxlev;
619}
620
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200621/*! Return string name of a given GSM Band */
Harald Weltecbc80622010-03-22 08:28:44 +0800622const char *gsm_band_name(enum gsm_band band)
Harald Welteaebe08c2010-03-04 10:39:17 +0100623{
624 switch (band) {
625 case GSM_BAND_450:
626 return "GSM450";
627 case GSM_BAND_480:
Sylvain Munaute10ae5b2010-07-04 11:41:36 +0200628 return "GSM480";
Harald Welteaebe08c2010-03-04 10:39:17 +0100629 case GSM_BAND_750:
630 return "GSM750";
631 case GSM_BAND_810:
632 return "GSM810";
633 case GSM_BAND_850:
634 return "GSM850";
635 case GSM_BAND_900:
636 return "GSM900";
637 case GSM_BAND_1800:
638 return "DCS1800";
639 case GSM_BAND_1900:
640 return "PCS1900";
641 }
642 return "invalid";
643}
644
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200645/*! Parse string name of a GSM band */
Harald Welteaebe08c2010-03-04 10:39:17 +0100646enum gsm_band gsm_band_parse(const char* mhz)
647{
Pau Espin Pedrol399a6f02017-06-18 14:07:37 +0200648 while (*mhz && !isdigit((unsigned char)*mhz))
Harald Welteaebe08c2010-03-04 10:39:17 +0100649 mhz++;
650
651 if (*mhz == '\0')
652 return -EINVAL;
653
Harald Welted3ff15f2010-03-07 18:23:47 +0100654 switch (strtol(mhz, NULL, 10)) {
Harald Welteaebe08c2010-03-04 10:39:17 +0100655 case 450:
656 return GSM_BAND_450;
657 case 480:
658 return GSM_BAND_480;
659 case 750:
660 return GSM_BAND_750;
661 case 810:
662 return GSM_BAND_810;
663 case 850:
664 return GSM_BAND_850;
665 case 900:
666 return GSM_BAND_900;
667 case 1800:
668 return GSM_BAND_1800;
669 case 1900:
670 return GSM_BAND_1900;
671 default:
672 return -EINVAL;
673 }
674}
675
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200676/*! Resolve GSM band from ARFCN
Harald Welte96e2a002017-06-12 21:44:18 +0200677 * In Osmocom, we use the highest bit of the \a arfcn to indicate PCS
678 * \param[in] arfcn Osmocom ARFCN, highest bit determines PCS mode
679 * \returns GSM Band */
Harald Welte622b7182010-03-07 17:50:21 +0100680enum gsm_band gsm_arfcn2band(uint16_t arfcn)
681{
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100682 int is_pcs = arfcn & ARFCN_PCS;
683
684 arfcn &= ~ARFCN_FLAG_MASK;
685
686 if (is_pcs)
Harald Welte622b7182010-03-07 17:50:21 +0100687 return GSM_BAND_1900;
688 else if (arfcn <= 124)
689 return GSM_BAND_900;
690 else if (arfcn >= 955 && arfcn <= 1023)
691 return GSM_BAND_900;
692 else if (arfcn >= 128 && arfcn <= 251)
693 return GSM_BAND_850;
694 else if (arfcn >= 512 && arfcn <= 885)
695 return GSM_BAND_1800;
696 else if (arfcn >= 259 && arfcn <= 293)
697 return GSM_BAND_450;
698 else if (arfcn >= 306 && arfcn <= 340)
699 return GSM_BAND_480;
700 else if (arfcn >= 350 && arfcn <= 425)
701 return GSM_BAND_810;
702 else if (arfcn >= 438 && arfcn <= 511)
703 return GSM_BAND_750;
704 else
705 return GSM_BAND_1800;
706}
707
Sylvain Munaut55720312012-12-11 23:44:41 +0100708struct gsm_freq_range {
709 uint16_t arfcn_first;
710 uint16_t arfcn_last;
711 uint16_t freq_ul_first;
712 uint16_t freq_dl_offset;
713 uint16_t flags;
714};
715
716static struct gsm_freq_range gsm_ranges[] = {
717 { 512, 810, 18502, 800, ARFCN_PCS }, /* PCS 1900 */
718 { 0, 124, 8900, 450, 0 }, /* P-GSM + E-GSM ARFCN 0 */
719 { 955, 1023, 8762, 450, 0 }, /* E-GSM + R-GSM */
720 { 128, 251, 8242, 450, 0 }, /* GSM 850 */
721 { 512, 885, 17102, 950, 0 }, /* DCS 1800 */
722 { 259, 293, 4506, 100, 0 }, /* GSM 450 */
723 { 306, 340, 4790, 100, 0 }, /* GSM 480 */
724 { 350, 425, 8060, 450, 0 }, /* GSM 810 */
725 { 438, 511, 7472, 300, 0 }, /* GSM 750 */
726 { /* Guard */ }
727};
728
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200729/*! Convert an ARFCN to the frequency in MHz * 10
Harald Welte96e2a002017-06-12 21:44:18 +0200730 * \param[in] arfcn GSM ARFCN to convert
731 * \param[in] uplink Uplink (1) or Downlink (0) frequency
732 * \returns Frequency in units of 1/10ths of MHz (100kHz) */
Harald Welte622b7182010-03-07 17:50:21 +0100733uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
734{
Sylvain Munaut55720312012-12-11 23:44:41 +0100735 struct gsm_freq_range *r;
736 uint16_t flags = arfcn & ARFCN_FLAG_MASK;
737 uint16_t freq10_ul = 0xffff;
738 uint16_t freq10_dl = 0xffff;
Harald Welte622b7182010-03-07 17:50:21 +0100739
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100740 arfcn &= ~ARFCN_FLAG_MASK;
741
Sylvain Munaut55720312012-12-11 23:44:41 +0100742 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
743 if ((flags == r->flags) &&
744 (arfcn >= r->arfcn_first) &&
745 (arfcn <= r->arfcn_last))
746 {
747 freq10_ul = r->freq_ul_first + 2 * (arfcn - r->arfcn_first);
748 freq10_dl = freq10_ul + r->freq_dl_offset;
749 break;
750 }
751 }
752
753 return uplink ? freq10_ul : freq10_dl;
754}
755
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200756/*! Convert a Frequency in MHz * 10 to ARFCN
Harald Welte96e2a002017-06-12 21:44:18 +0200757 * \param[in] freq10 Frequency in units of 1/10ths of MHz (100kHz)
758 * \param[in] uplink Frequency is Uplink (1) or Downlink (0)
759 * \returns ARFCN in case of success; 0xffff on error */
Sylvain Munaut55720312012-12-11 23:44:41 +0100760uint16_t gsm_freq102arfcn(uint16_t freq10, int uplink)
761{
762 struct gsm_freq_range *r;
763 uint16_t freq10_lo, freq10_hi;
764 uint16_t arfcn = 0xffff;
765
766 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
767 /* Generate frequency limits */
768 freq10_lo = r->freq_ul_first;
769 freq10_hi = freq10_lo + 2 * (r->arfcn_last - r->arfcn_first);
770 if (!uplink) {
771 freq10_lo += r->freq_dl_offset;
772 freq10_hi += r->freq_dl_offset;
773 }
774
775 /* Check if this fits */
776 if (freq10 >= freq10_lo && freq10 <= freq10_hi) {
777 arfcn = r->arfcn_first + ((freq10 - freq10_lo) >> 1);
778 arfcn |= r->flags;
779 break;
780 }
781 }
Harald Welte622b7182010-03-07 17:50:21 +0100782
783 if (uplink)
Sylvain Munaut55720312012-12-11 23:44:41 +0100784 arfcn |= ARFCN_UPLINK;
785
786 return arfcn;
Harald Welte622b7182010-03-07 17:50:21 +0100787}
788
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200789/*! Parse GSM Frame Number into struct \ref gsm_time
Harald Welte96e2a002017-06-12 21:44:18 +0200790 * \param[out] time Caller-provided memory for \ref gsm_time
791 * \param[in] fn GSM Frame Number */
Harald Welte622b7182010-03-07 17:50:21 +0100792void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
793{
794 time->fn = fn;
795 time->t1 = time->fn / (26*51);
796 time->t2 = time->fn % 26;
797 time->t3 = time->fn % 51;
798 time->tc = (time->fn / 51) % 8;
799}
800
Philipp Maierb808da42017-06-26 10:50:28 +0200801/*! Parse GSM Frame Number into printable string
802 * \param[in] fn GSM Frame Number
803 * \returns pointer to printable string */
804char *gsm_fn_as_gsmtime_str(uint32_t fn)
805{
806 struct gsm_time time;
807
808 gsm_fn2gsmtime(&time, fn);
809 return osmo_dump_gsmtime(&time);
810}
811
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200812/*! Encode decoded \ref gsm_time to Frame Number
Harald Welte96e2a002017-06-12 21:44:18 +0200813 * \param[in] time GSM Time in decoded structure
814 * \returns GSM Frame Number */
Harald Welte622b7182010-03-07 17:50:21 +0100815uint32_t gsm_gsmtime2fn(struct gsm_time *time)
816{
817 /* TS 05.02 Chapter 4.3.3 TDMA frame number */
818 return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
819}
Harald Weltea1c4f762010-05-01 11:59:42 +0200820
Pau Espin Pedrol363130f2017-07-03 10:42:42 +0200821char *osmo_dump_gsmtime(const struct gsm_time *tm)
822{
823 static char buf[64];
824
825 snprintf(buf, sizeof(buf), "%06"PRIu32"/%02"PRIu16"/%02"PRIu8"/%02"PRIu8"/%02"PRIu8,
826 tm->fn, tm->t1, tm->t2, tm->t3, (uint8_t)tm->fn%52);
827 buf[sizeof(buf)-1] = '\0';
828 return buf;
829}
830
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200831/*! append range1024 encoded data to bit vector
Harald Welte96e2a002017-06-12 21:44:18 +0200832 * \param[out] bv Caller-provided output bit-vector
833 * \param[in] r Input Range1024 sructure */
Max8a5346b2016-04-22 19:28:09 +0200834void bitvec_add_range1024(struct bitvec *bv, const struct gsm48_range_1024 *r)
835{
836 bitvec_set_uint(bv, r->w1_hi, 2);
837 bitvec_set_uint(bv, r->w1_lo, 8);
838 bitvec_set_uint(bv, r->w2_hi, 8);
839 bitvec_set_uint(bv, r->w2_lo, 1);
840 bitvec_set_uint(bv, r->w3_hi, 7);
841 bitvec_set_uint(bv, r->w3_lo, 2);
842 bitvec_set_uint(bv, r->w4_hi, 6);
843 bitvec_set_uint(bv, r->w4_lo, 2);
844 bitvec_set_uint(bv, r->w5_hi, 6);
845 bitvec_set_uint(bv, r->w5_lo, 2);
846 bitvec_set_uint(bv, r->w6_hi, 6);
847 bitvec_set_uint(bv, r->w6_lo, 2);
848 bitvec_set_uint(bv, r->w7_hi, 6);
849 bitvec_set_uint(bv, r->w7_lo, 2);
850 bitvec_set_uint(bv, r->w8_hi, 6);
851 bitvec_set_uint(bv, r->w8_lo, 1);
852 bitvec_set_uint(bv, r->w9, 7);
853 bitvec_set_uint(bv, r->w10, 7);
854 bitvec_set_uint(bv, r->w11_hi, 1);
855 bitvec_set_uint(bv, r->w11_lo, 6);
856 bitvec_set_uint(bv, r->w12_hi, 2);
857 bitvec_set_uint(bv, r->w12_lo, 5);
858 bitvec_set_uint(bv, r->w13_hi, 3);
859 bitvec_set_uint(bv, r->w13_lo, 4);
860 bitvec_set_uint(bv, r->w14_hi, 4);
861 bitvec_set_uint(bv, r->w14_lo, 3);
862 bitvec_set_uint(bv, r->w15_hi, 5);
863 bitvec_set_uint(bv, r->w15_lo, 2);
864 bitvec_set_uint(bv, r->w16, 6);
865}
866
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200867/*! Determine GPRS TLLI Type (TS 23.003 Chapter 2.6) */
Harald Weltea1c4f762010-05-01 11:59:42 +0200868int gprs_tlli_type(uint32_t tlli)
869{
870 if ((tlli & 0xc0000000) == 0xc0000000)
871 return TLLI_LOCAL;
872 else if ((tlli & 0xc0000000) == 0x80000000)
873 return TLLI_FOREIGN;
874 else if ((tlli & 0xf8000000) == 0x78000000)
875 return TLLI_RANDOM;
876 else if ((tlli & 0xf8000000) == 0x70000000)
877 return TLLI_AUXILIARY;
Harald Welte1f6aad12015-08-15 19:51:45 +0200878 else if ((tlli & 0xf0000000) == 0x00000000)
879 return TLLI_G_RNTI;
880 else if ((tlli & 0xf0000000) == 0x10000000)
881 return TLLI_RAND_G_RNTI;
Harald Weltea1c4f762010-05-01 11:59:42 +0200882
883 return TLLI_RESERVED;
884}
Harald Weltec2263172010-06-01 10:47:07 +0200885
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200886/*! Determine TLLI from P-TMSI
Harald Welte96e2a002017-06-12 21:44:18 +0200887 * \param[in] p_tmsi P-TMSI
888 * \param[in] type TLLI Type we want to derive from \a p_tmsi
889 * \returns TLLI of given type */
Harald Weltec2263172010-06-01 10:47:07 +0200890uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
891{
892 uint32_t tlli;
893 switch (type) {
894 case TLLI_LOCAL:
895 tlli = p_tmsi | 0xc0000000;
896 break;
897 case TLLI_FOREIGN:
898 tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
899 break;
900 default:
901 tlli = 0;
902 break;
903 }
904 return tlli;
905}
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200906
907/* Wrappers for deprecated functions: */
908
909int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l)
910{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100911 gsm_7bit_decode_n(text, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
912 user_data, septet_l);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200913
914 /* Mimic the original behaviour. */
915 return septet_l;
916}
917
918int gsm_7bit_decode_ussd(char *text, const uint8_t *user_data, uint8_t length)
919{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100920 return gsm_7bit_decode_n_ussd(text, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
921 user_data, length);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200922}
923
924int gsm_7bit_encode(uint8_t *result, const char *data)
925{
926 int out;
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100927 return gsm_7bit_encode_n(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
928 data, &out);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200929}
930
931int gsm_7bit_encode_ussd(uint8_t *result, const char *data, int *octets)
932{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100933 return gsm_7bit_encode_n_ussd(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
934 data, octets);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200935}
936
937int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets)
938{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100939 return gsm_7bit_encode_n(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
940 data, octets);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200941}