blob: e8e452f8c611a0c27a0083606769a0e15ceffabb [file] [log] [blame]
Harald Welteec8b4502010-02-20 20:34:29 +01001/*
2 * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +02003 * (C) 2009,2013 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte622b7182010-03-07 17:50:21 +01004 * (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
Nico Goldec56a56d2012-09-18 14:29:40 +02005 * (C) 2010-2012 by Nico Golde <nico@ngolde.de>
Harald Welteec8b4502010-02-20 20:34:29 +01006 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
Harald Welted38c8b82011-08-30 11:32:56 +020025/*! \mainpage libosmogsm Documentation
26 *
27 * \section sec_intro Introduction
28 * This library is a collection of common code used in various
29 * GSM related sub-projects inside the Osmocom family of projects. It
30 * includes A5/1 and A5/2 ciphers, COMP128v1, a LAPDm implementation,
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +020031 * a GSM TLV parser, SMS utility routines as well as
Harald Welted38c8b82011-08-30 11:32:56 +020032 * protocol definitions for a series of protocols:
33 * * Um L2 (04.06)
34 * * Um L3 (04.08)
35 * * A-bis RSL (08.58)
36 * * A-bis OML (08.59, 12.21)
37 * * A (08.08)
38 * \n\n
39 * Please note that C language projects inside Osmocom are typically
40 * single-threaded event-loop state machine designs. As such,
41 * routines in libosmogsm are not thread-safe. If you must use them in
42 * a multi-threaded context, you have to add your own locking.
43 *
44 * \section sec_copyright Copyright and License
45 * Copyright © 2008-2011 - Harald Welte, Holger Freyther and contributors\n
46 * All rights reserved. \n\n
47 * The source code of libosmogsm is licensed under the terms of the GNU
48 * General Public License as published by the Free Software Foundation;
49 * either version 2 of the License, or (at your option) any later
50 * version.\n
51 * See <http://www.gnu.org/licenses/> or COPYING included in the source
52 * code package istelf.\n
53 * The information detailed here is provided AS IS with NO WARRANTY OF
54 * ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND
55 * FITNESS FOR A PARTICULAR PURPOSE.
56 * \n\n
57 *
58 * \section sec_contact Contact and Support
59 * Community-based support is available at the OpenBSC mailing list
60 * <http://lists.osmocom.org/mailman/listinfo/openbsc>\n
61 * Commercial support options available upon request from
62 * <http://sysmocom.de/>
63 */
64
Harald Welteec8b4502010-02-20 20:34:29 +010065//#include <openbsc/gsm_data.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010066#include <osmocom/core/utils.h>
67#include <osmocom/gsm/gsm_utils.h>
Harald Welteec8b4502010-02-20 20:34:29 +010068
69#include <stdlib.h>
70#include <stdint.h>
71#include <string.h>
72#include <stdio.h>
73#include <errno.h>
Harald Welteaebe08c2010-03-04 10:39:17 +010074#include <ctype.h>
Harald Welteec8b4502010-02-20 20:34:29 +010075
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010076#include "../../config.h"
Harald Welteec8b4502010-02-20 20:34:29 +010077
Holger Hans Peter Freytherdd02a472010-07-23 16:35:00 +080078/* ETSI GSM 03.38 6.2.1 and 6.2.1.1 default alphabet
79 * Greek symbols at hex positions 0x10 and 0x12-0x1a
80 * left out as they can't be handled with a char and
81 * since most phones don't display or write these
82 * characters this would only needlessly make the code
Jacob Erlbeck18109252013-08-12 17:07:54 +020083 * more complex.
84 *
85 * Note that this table contains the latin1->7bit mapping _and_ has
86 * been merged with the reverse mapping (7bit->latin1) for the
87 * extended characters at offset 0x7f.
88 */
Holger Hans Peter Freytherdd02a472010-07-23 16:35:00 +080089static unsigned char gsm_7bit_alphabet[] = {
90 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0x0d, 0xff,
91 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
92 0xff, 0xff, 0x20, 0x21, 0x22, 0x23, 0x02, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
93 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
94 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
95 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
96 0x5a, 0x3c, 0x2f, 0x3e, 0x14, 0x11, 0xff, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
97 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
98 0x78, 0x79, 0x7a, 0x28, 0x40, 0x29, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
99 0xff, 0xff, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff,
100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0xff, 0x01, 0xff,
101 0x03, 0xff, 0x7b, 0x7d, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff,
102 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5b, 0x7e, 0x5d, 0xff, 0x7c, 0xff, 0xff, 0xff,
103 0xff, 0x5b, 0x0e, 0x1c, 0x09, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5d,
104 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0x0b, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff, 0x1e, 0x7f,
105 0xff, 0xff, 0xff, 0x7b, 0x0f, 0x1d, 0xff, 0x04, 0x05, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff,
106 0xff, 0x7d, 0x08, 0xff, 0xff, 0xff, 0x7c, 0xff, 0x0c, 0x06, 0xff, 0xff, 0x7e, 0xff, 0xff
107};
108
Nico Golde28de0532010-07-09 17:19:12 +0200109/* GSM 03.38 6.2.1 Character lookup for decoding */
110static int gsm_septet_lookup(uint8_t ch)
111{
112 int i = 0;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200113 for (; i < sizeof(gsm_7bit_alphabet); i++) {
114 if (gsm_7bit_alphabet[i] == ch)
Nico Golde28de0532010-07-09 17:19:12 +0200115 return i;
116 }
117 return -1;
118}
119
Dennis Wehrle291e6132011-07-24 20:14:13 +0200120/* Compute the number of octets from the number of septets, for instance: 47 septets needs 41,125 = 42 octets */
121uint8_t gsm_get_octet_len(const uint8_t sept_len){
122 int octet_len = (sept_len * 7) / 8;
123 if ((sept_len * 7) % 8 != 0)
124 octet_len++;
125
126 return octet_len;
127}
128
Nico Golde28de0532010-07-09 17:19:12 +0200129/* GSM 03.38 6.2.1 Character unpacking */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200130int 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 +0100131{
Maxcf37c4c2016-01-21 16:52:40 +0100132 unsigned shift = 0;
133 uint8_t c7, c8, next_is_ext = 0, lu, ru;
134 const uint8_t maxlen = gsm_get_octet_len(septet_l);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200135 const char *text_buf_begin = text;
136 const char *text_buf_end = text + n;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200137
138 OSMO_ASSERT (n > 0);
Harald Welteec8b4502010-02-20 20:34:29 +0100139
Dennis Wehrle291e6132011-07-24 20:14:13 +0200140 /* skip the user data header */
141 if (ud_hdr_ind) {
142 /* get user data header length + 1 (for the 'user data header length'-field) */
143 shift = ((user_data[0] + 1) * 8) / 7;
144 if ((((user_data[0] + 1) * 8) % 7) != 0)
145 shift++;
146 septet_l = septet_l - shift;
147 }
148
Maxcf37c4c2016-01-21 16:52:40 +0100149 unsigned i, l, r;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200150 for (i = 0; i < septet_l && text != text_buf_end - 1; i++) {
Maxcf37c4c2016-01-21 16:52:40 +0100151
152 l = ((i + shift) * 7 + 7) >> 3;
153 r = ((i + shift) * 7) >> 3;
154
155 /* the left side index is always >= right side index
156 sometimes it even gets beyond array boundary
157 check for that explicitly and force 0 instead
158 */
159 if (l >= maxlen)
160 lu = 0;
161 else
162 lu = user_data[l] << (7 - (((i + shift) * 7 + 7) & 7));
163
164 ru = user_data[r] >> (((i + shift) * 7) & 7);
165
166 c7 = (lu | ru) & 0x7f;
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200167
Harald Weltebe55a8b2012-09-20 10:00:25 +0200168 if (next_is_ext) {
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200169 /* this is an extension character */
Nico Goldec56a56d2012-09-18 14:29:40 +0200170 next_is_ext = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200171 c8 = gsm_7bit_alphabet[0x7f + c7];
172 } else if (c7 == 0x1b && i + 1 < septet_l) {
173 next_is_ext = 1;
Nico Golde5b67a042012-09-20 16:56:23 +0200174 continue;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200175 } else {
176 c8 = gsm_septet_lookup(c7);
Nico Golde5b67a042012-09-20 16:56:23 +0200177 }
178
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200179 *(text++) = c8;
Harald Welteec8b4502010-02-20 20:34:29 +0100180 }
181
Nico Golde28de0532010-07-09 17:19:12 +0200182 *text = '\0';
Nico Golde28de0532010-07-09 17:19:12 +0200183
Maxcf37c4c2016-01-21 16:52:40 +0100184 return text - text_buf_begin;
Nico Golde28de0532010-07-09 17:19:12 +0200185}
186
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200187int 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 +0200188{
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200189 return gsm_7bit_decode_n_hdr(text, n, user_data, septet_l, 0);
Dennis Wehrle291e6132011-07-24 20:14:13 +0200190}
191
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200192int 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 +0200193{
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200194 int nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +0200195
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200196 nchars = gsm_7bit_decode_n_hdr(text, n, user_data, length, 0);
Andreas Eversberg95975552013-08-08 12:38:53 +0200197 /* remove last <CR>, if it fits up to the end of last octet */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200198 if (nchars && (user_data[gsm_get_octet_len(length) - 1] >> 1) == '\r')
199 text[--nchars] = '\0';
Andreas Eversberg95975552013-08-08 12:38:53 +0200200
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200201 return nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +0200202}
203
Nico Golde28de0532010-07-09 17:19:12 +0200204/* GSM 03.38 6.2.1 Prepare character packing */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200205int gsm_septet_encode(uint8_t *result, const char *data)
Nico Golde28de0532010-07-09 17:19:12 +0200206{
207 int i, y = 0;
208 uint8_t ch;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200209 for (i = 0; i < strlen(data); i++) {
Nico Golde28de0532010-07-09 17:19:12 +0200210 ch = data[i];
211 switch(ch){
212 /* fall-through for extension characters */
213 case 0x0c:
214 case 0x5e:
215 case 0x7b:
216 case 0x7d:
217 case 0x5c:
218 case 0x5b:
219 case 0x7e:
220 case 0x5d:
221 case 0x7c:
222 result[y++] = 0x1b;
223 default:
224 result[y] = gsm_7bit_alphabet[ch];
225 break;
226 }
227 y++;
228 }
229
230 return y;
231}
232
Dennis Wehrle291e6132011-07-24 20:14:13 +0200233/* 7bit to octet packing */
Harald Welteca693882013-03-13 15:10:55 +0100234int gsm_septets2octets(uint8_t *result, const uint8_t *rdata, uint8_t septet_len, uint8_t padding)
235{
Dennis Wehrle291e6132011-07-24 20:14:13 +0200236 int i = 0, z = 0;
Nico Golde28de0532010-07-09 17:19:12 +0200237 uint8_t cb, nb;
238 int shift = 0;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200239 uint8_t *data = calloc(septet_len + 1, sizeof(uint8_t));
Nico Golde28de0532010-07-09 17:19:12 +0200240
Dennis Wehrle291e6132011-07-24 20:14:13 +0200241 if (padding) {
242 shift = 7 - padding;
243 /* the first zero is needed for padding */
244 memcpy(data + 1, rdata, septet_len);
245 septet_len++;
246 } else
247 memcpy(data, rdata, septet_len);
Nico Golde28de0532010-07-09 17:19:12 +0200248
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200249 for (i = 0; i < septet_len; i++) {
Dennis Wehrle291e6132011-07-24 20:14:13 +0200250 if (shift == 7) {
251 /*
252 * special end case with the. This is necessary if the
253 * last septet fits into the previous octet. E.g. 48
254 * non-extension characters:
255 * ....ag ( a = 1100001, g = 1100111)
256 * result[40] = 100001 XX, result[41] = 1100111 1 */
257 if (i + 1 < septet_len) {
258 shift = 0;
259 continue;
260 } else if (i + 1 == septet_len)
261 break;
Nico Golde28de0532010-07-09 17:19:12 +0200262 }
263
Dennis Wehrle291e6132011-07-24 20:14:13 +0200264 cb = (data[i] & 0x7f) >> shift;
265 if (i + 1 < septet_len) {
266 nb = (data[i + 1] & 0x7f) << (7 - shift);
Nico Golde28de0532010-07-09 17:19:12 +0200267 cb = cb | nb;
268 }
269
270 result[z++] = cb;
Nico Golde28de0532010-07-09 17:19:12 +0200271 shift++;
272 }
273
Dennis Wehrle291e6132011-07-24 20:14:13 +0200274 free(data);
275
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200276 return z;
Harald Welteec8b4502010-02-20 20:34:29 +0100277}
278
Dennis Wehrle291e6132011-07-24 20:14:13 +0200279/* GSM 03.38 6.2.1 Character packing */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200280int gsm_7bit_encode_n(uint8_t *result, size_t n, const char *data, int *octets)
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +0200281{
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200282 int y = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200283 int o;
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100284 size_t max_septets = n * 8 / 7;
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200285
Dennis Wehrle291e6132011-07-24 20:14:13 +0200286 /* prepare for the worst case, every character expanding to two bytes */
287 uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
288 y = gsm_septet_encode(rdata, data);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200289
290 if (y > max_septets) {
291 /*
292 * Limit the number of septets to avoid the generation
293 * of more than n octets.
294 */
295 y = max_septets;
296 }
297
298 o = gsm_septets2octets(result, rdata, y, 0);
299
300 if (octets)
301 *octets = o;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200302
303 free(rdata);
304
305 /*
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200306 * We don't care about the number of octets, because they are not
Dennis Wehrle291e6132011-07-24 20:14:13 +0200307 * unique. E.g.:
308 * 1.) 46 non-extension characters + 1 extension character
309 * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets
310 * 2.) 47 non-extension characters
311 * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets
312 * 3.) 48 non-extension characters
313 * => (48 * 7 bit) / 8 bit = 42 octects
314 */
315 return y;
316}
317
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200318int gsm_7bit_encode_n_ussd(uint8_t *result, size_t n, const char *data, int *octets)
319{
320 int y;
321
322 y = gsm_7bit_encode_n(result, n, data, octets);
323 /* if last octet contains only one bit, add <CR> */
324 if (((y * 7) & 7) == 1)
325 result[(*octets) - 1] |= ('\r' << 1);
326 /* if last character is <CR> and completely fills last octet, add
327 * another <CR>. */
328 if (y && ((y * 7) & 7) == 0 && (result[(*octets) - 1] >> 1) == '\r' && *octets < n - 1) {
329 result[(*octets)++] = '\r';
330 y++;
331 }
332
333 return y;
334}
335
Andreas Eversberg2a68c7c2011-06-26 11:41:48 +0200336/* convert power class to dBm according to GSM TS 05.05 */
337unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class)
338{
339 switch (band) {
340 case GSM_BAND_450:
341 case GSM_BAND_480:
342 case GSM_BAND_750:
343 case GSM_BAND_900:
344 case GSM_BAND_810:
345 case GSM_BAND_850:
346 if (class == 1)
347 return 43; /* 20W */
348 if (class == 2)
349 return 39; /* 8W */
350 if (class == 3)
351 return 37; /* 5W */
352 if (class == 4)
353 return 33; /* 2W */
354 if (class == 5)
355 return 29; /* 0.8W */
356 break;
357 case GSM_BAND_1800:
358 if (class == 1)
359 return 30; /* 1W */
360 if (class == 2)
361 return 24; /* 0.25W */
362 if (class == 3)
363 return 36; /* 4W */
364 break;
365 case GSM_BAND_1900:
366 if (class == 1)
367 return 30; /* 1W */
368 if (class == 2)
369 return 24; /* 0.25W */
370 if (class == 3)
371 return 33; /* 2W */
372 break;
373 }
374 return -EINVAL;
375}
376
Harald Welteec8b4502010-02-20 20:34:29 +0100377/* determine power control level for given dBm value, as indicated
378 * by the tables in chapter 4.1.1 of GSM TS 05.05 */
379int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
380{
381 switch (band) {
382 case GSM_BAND_450:
383 case GSM_BAND_480:
384 case GSM_BAND_750:
385 case GSM_BAND_900:
386 case GSM_BAND_810:
387 case GSM_BAND_850:
388 if (dbm >= 39)
389 return 0;
390 else if (dbm < 5)
391 return 19;
392 else {
393 /* we are guaranteed to have (5 <= dbm < 39) */
394 return 2 + ((39 - dbm) / 2);
395 }
396 break;
397 case GSM_BAND_1800:
398 if (dbm >= 36)
399 return 29;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200400 else if (dbm >= 34)
Harald Welteec8b4502010-02-20 20:34:29 +0100401 return 30;
402 else if (dbm >= 32)
403 return 31;
404 else if (dbm == 31)
405 return 0;
406 else {
407 /* we are guaranteed to have (0 <= dbm < 31) */
408 return (30 - dbm) / 2;
409 }
410 break;
411 case GSM_BAND_1900:
412 if (dbm >= 33)
413 return 30;
414 else if (dbm >= 32)
415 return 31;
416 else if (dbm == 31)
417 return 0;
418 else {
419 /* we are guaranteed to have (0 <= dbm < 31) */
420 return (30 - dbm) / 2;
421 }
422 break;
423 }
424 return -EINVAL;
425}
426
427int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
428{
429 lvl &= 0x1f;
430
431 switch (band) {
432 case GSM_BAND_450:
433 case GSM_BAND_480:
434 case GSM_BAND_750:
435 case GSM_BAND_900:
436 case GSM_BAND_810:
437 case GSM_BAND_850:
438 if (lvl < 2)
439 return 39;
440 else if (lvl < 20)
441 return 39 - ((lvl - 2) * 2) ;
442 else
443 return 5;
444 break;
445 case GSM_BAND_1800:
446 if (lvl < 16)
447 return 30 - (lvl * 2);
448 else if (lvl < 29)
449 return 0;
450 else
451 return 36 - ((lvl - 29) * 2);
452 break;
453 case GSM_BAND_1900:
454 if (lvl < 16)
455 return 30 - (lvl * 2);
456 else if (lvl < 30)
457 return -EINVAL;
458 else
459 return 33 - (lvl - 30);
460 break;
461 }
462 return -EINVAL;
463}
464
Bhaskar6b30f922013-05-16 17:35:49 +0530465/* According to TS 05.08 Chapter 8.1.4 */
Harald Welteec8b4502010-02-20 20:34:29 +0100466int rxlev2dbm(uint8_t rxlev)
467{
468 if (rxlev > 63)
469 rxlev = 63;
470
471 return -110 + rxlev;
472}
473
Bhaskar6b30f922013-05-16 17:35:49 +0530474/* According to TS 05.08 Chapter 8.1.4 */
Harald Welteec8b4502010-02-20 20:34:29 +0100475uint8_t dbm2rxlev(int dbm)
476{
477 int rxlev = dbm + 110;
478
479 if (rxlev > 63)
480 rxlev = 63;
481 else if (rxlev < 0)
482 rxlev = 0;
483
484 return rxlev;
485}
486
Harald Weltecbc80622010-03-22 08:28:44 +0800487const char *gsm_band_name(enum gsm_band band)
Harald Welteaebe08c2010-03-04 10:39:17 +0100488{
489 switch (band) {
490 case GSM_BAND_450:
491 return "GSM450";
492 case GSM_BAND_480:
Sylvain Munaute10ae5b2010-07-04 11:41:36 +0200493 return "GSM480";
Harald Welteaebe08c2010-03-04 10:39:17 +0100494 case GSM_BAND_750:
495 return "GSM750";
496 case GSM_BAND_810:
497 return "GSM810";
498 case GSM_BAND_850:
499 return "GSM850";
500 case GSM_BAND_900:
501 return "GSM900";
502 case GSM_BAND_1800:
503 return "DCS1800";
504 case GSM_BAND_1900:
505 return "PCS1900";
506 }
507 return "invalid";
508}
509
510enum gsm_band gsm_band_parse(const char* mhz)
511{
512 while (*mhz && !isdigit(*mhz))
513 mhz++;
514
515 if (*mhz == '\0')
516 return -EINVAL;
517
Harald Welted3ff15f2010-03-07 18:23:47 +0100518 switch (strtol(mhz, NULL, 10)) {
Harald Welteaebe08c2010-03-04 10:39:17 +0100519 case 450:
520 return GSM_BAND_450;
521 case 480:
522 return GSM_BAND_480;
523 case 750:
524 return GSM_BAND_750;
525 case 810:
526 return GSM_BAND_810;
527 case 850:
528 return GSM_BAND_850;
529 case 900:
530 return GSM_BAND_900;
531 case 1800:
532 return GSM_BAND_1800;
533 case 1900:
534 return GSM_BAND_1900;
535 default:
536 return -EINVAL;
537 }
538}
539
Harald Welte622b7182010-03-07 17:50:21 +0100540enum gsm_band gsm_arfcn2band(uint16_t arfcn)
541{
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100542 int is_pcs = arfcn & ARFCN_PCS;
543
544 arfcn &= ~ARFCN_FLAG_MASK;
545
546 if (is_pcs)
Harald Welte622b7182010-03-07 17:50:21 +0100547 return GSM_BAND_1900;
548 else if (arfcn <= 124)
549 return GSM_BAND_900;
550 else if (arfcn >= 955 && arfcn <= 1023)
551 return GSM_BAND_900;
552 else if (arfcn >= 128 && arfcn <= 251)
553 return GSM_BAND_850;
554 else if (arfcn >= 512 && arfcn <= 885)
555 return GSM_BAND_1800;
556 else if (arfcn >= 259 && arfcn <= 293)
557 return GSM_BAND_450;
558 else if (arfcn >= 306 && arfcn <= 340)
559 return GSM_BAND_480;
560 else if (arfcn >= 350 && arfcn <= 425)
561 return GSM_BAND_810;
562 else if (arfcn >= 438 && arfcn <= 511)
563 return GSM_BAND_750;
564 else
565 return GSM_BAND_1800;
566}
567
Sylvain Munaut55720312012-12-11 23:44:41 +0100568struct gsm_freq_range {
569 uint16_t arfcn_first;
570 uint16_t arfcn_last;
571 uint16_t freq_ul_first;
572 uint16_t freq_dl_offset;
573 uint16_t flags;
574};
575
576static struct gsm_freq_range gsm_ranges[] = {
577 { 512, 810, 18502, 800, ARFCN_PCS }, /* PCS 1900 */
578 { 0, 124, 8900, 450, 0 }, /* P-GSM + E-GSM ARFCN 0 */
579 { 955, 1023, 8762, 450, 0 }, /* E-GSM + R-GSM */
580 { 128, 251, 8242, 450, 0 }, /* GSM 850 */
581 { 512, 885, 17102, 950, 0 }, /* DCS 1800 */
582 { 259, 293, 4506, 100, 0 }, /* GSM 450 */
583 { 306, 340, 4790, 100, 0 }, /* GSM 480 */
584 { 350, 425, 8060, 450, 0 }, /* GSM 810 */
585 { 438, 511, 7472, 300, 0 }, /* GSM 750 */
586 { /* Guard */ }
587};
588
Harald Welte622b7182010-03-07 17:50:21 +0100589/* Convert an ARFCN to the frequency in MHz * 10 */
590uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
591{
Sylvain Munaut55720312012-12-11 23:44:41 +0100592 struct gsm_freq_range *r;
593 uint16_t flags = arfcn & ARFCN_FLAG_MASK;
594 uint16_t freq10_ul = 0xffff;
595 uint16_t freq10_dl = 0xffff;
Harald Welte622b7182010-03-07 17:50:21 +0100596
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100597 arfcn &= ~ARFCN_FLAG_MASK;
598
Sylvain Munaut55720312012-12-11 23:44:41 +0100599 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
600 if ((flags == r->flags) &&
601 (arfcn >= r->arfcn_first) &&
602 (arfcn <= r->arfcn_last))
603 {
604 freq10_ul = r->freq_ul_first + 2 * (arfcn - r->arfcn_first);
605 freq10_dl = freq10_ul + r->freq_dl_offset;
606 break;
607 }
608 }
609
610 return uplink ? freq10_ul : freq10_dl;
611}
612
613/* Convert a Frequency in MHz * 10 to ARFCN */
614uint16_t gsm_freq102arfcn(uint16_t freq10, int uplink)
615{
616 struct gsm_freq_range *r;
617 uint16_t freq10_lo, freq10_hi;
618 uint16_t arfcn = 0xffff;
619
620 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
621 /* Generate frequency limits */
622 freq10_lo = r->freq_ul_first;
623 freq10_hi = freq10_lo + 2 * (r->arfcn_last - r->arfcn_first);
624 if (!uplink) {
625 freq10_lo += r->freq_dl_offset;
626 freq10_hi += r->freq_dl_offset;
627 }
628
629 /* Check if this fits */
630 if (freq10 >= freq10_lo && freq10 <= freq10_hi) {
631 arfcn = r->arfcn_first + ((freq10 - freq10_lo) >> 1);
632 arfcn |= r->flags;
633 break;
634 }
635 }
Harald Welte622b7182010-03-07 17:50:21 +0100636
637 if (uplink)
Sylvain Munaut55720312012-12-11 23:44:41 +0100638 arfcn |= ARFCN_UPLINK;
639
640 return arfcn;
Harald Welte622b7182010-03-07 17:50:21 +0100641}
642
643void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
644{
645 time->fn = fn;
646 time->t1 = time->fn / (26*51);
647 time->t2 = time->fn % 26;
648 time->t3 = time->fn % 51;
649 time->tc = (time->fn / 51) % 8;
650}
651
652uint32_t gsm_gsmtime2fn(struct gsm_time *time)
653{
654 /* TS 05.02 Chapter 4.3.3 TDMA frame number */
655 return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
656}
Harald Weltea1c4f762010-05-01 11:59:42 +0200657
Harald Welte1f6aad12015-08-15 19:51:45 +0200658/* TS 23.003 Chapter 2.6 */
Harald Weltea1c4f762010-05-01 11:59:42 +0200659int gprs_tlli_type(uint32_t tlli)
660{
661 if ((tlli & 0xc0000000) == 0xc0000000)
662 return TLLI_LOCAL;
663 else if ((tlli & 0xc0000000) == 0x80000000)
664 return TLLI_FOREIGN;
665 else if ((tlli & 0xf8000000) == 0x78000000)
666 return TLLI_RANDOM;
667 else if ((tlli & 0xf8000000) == 0x70000000)
668 return TLLI_AUXILIARY;
Harald Welte1f6aad12015-08-15 19:51:45 +0200669 else if ((tlli & 0xf0000000) == 0x00000000)
670 return TLLI_G_RNTI;
671 else if ((tlli & 0xf0000000) == 0x10000000)
672 return TLLI_RAND_G_RNTI;
Harald Weltea1c4f762010-05-01 11:59:42 +0200673
674 return TLLI_RESERVED;
675}
Harald Weltec2263172010-06-01 10:47:07 +0200676
677uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
678{
679 uint32_t tlli;
680 switch (type) {
681 case TLLI_LOCAL:
682 tlli = p_tmsi | 0xc0000000;
683 break;
684 case TLLI_FOREIGN:
685 tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
686 break;
687 default:
688 tlli = 0;
689 break;
690 }
691 return tlli;
692}
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200693
694/* Wrappers for deprecated functions: */
695
696int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l)
697{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100698 gsm_7bit_decode_n(text, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
699 user_data, septet_l);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200700
701 /* Mimic the original behaviour. */
702 return septet_l;
703}
704
705int gsm_7bit_decode_ussd(char *text, const uint8_t *user_data, uint8_t length)
706{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100707 return gsm_7bit_decode_n_ussd(text, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
708 user_data, length);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200709}
710
711int gsm_7bit_encode(uint8_t *result, const char *data)
712{
713 int out;
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100714 return gsm_7bit_encode_n(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
715 data, &out);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200716}
717
718int gsm_7bit_encode_ussd(uint8_t *result, const char *data, int *octets)
719{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100720 return gsm_7bit_encode_n_ussd(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
721 data, octets);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200722}
723
724int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets)
725{
Jacob Erlbeck26cbd452014-01-07 13:39:24 +0100726 return gsm_7bit_encode_n(result, GSM_7BIT_LEGACY_MAX_BUFFER_SIZE,
727 data, octets);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200728}