blob: e248078f5152f1ad1f0a205586faa6136720ef3f [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
83 * more complex
84*/
85static unsigned char gsm_7bit_alphabet[] = {
86 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0x0d, 0xff,
87 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
88 0xff, 0xff, 0x20, 0x21, 0x22, 0x23, 0x02, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
89 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
90 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
91 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
92 0x5a, 0x3c, 0x2f, 0x3e, 0x14, 0x11, 0xff, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
93 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
94 0x78, 0x79, 0x7a, 0x28, 0x40, 0x29, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
95 0xff, 0xff, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff,
96 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0xff, 0x01, 0xff,
97 0x03, 0xff, 0x7b, 0x7d, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff,
98 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5b, 0x7e, 0x5d, 0xff, 0x7c, 0xff, 0xff, 0xff,
99 0xff, 0x5b, 0x0e, 0x1c, 0x09, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5d,
100 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0x0b, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff, 0x1e, 0x7f,
101 0xff, 0xff, 0xff, 0x7b, 0x0f, 0x1d, 0xff, 0x04, 0x05, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff,
102 0xff, 0x7d, 0x08, 0xff, 0xff, 0xff, 0x7c, 0xff, 0x0c, 0x06, 0xff, 0xff, 0x7e, 0xff, 0xff
103};
104
Nico Golde28de0532010-07-09 17:19:12 +0200105/* GSM 03.38 6.2.1 Character lookup for decoding */
106static int gsm_septet_lookup(uint8_t ch)
107{
108 int i = 0;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200109 for (; i < sizeof(gsm_7bit_alphabet); i++) {
110 if (gsm_7bit_alphabet[i] == ch)
Nico Golde28de0532010-07-09 17:19:12 +0200111 return i;
112 }
113 return -1;
114}
115
Dennis Wehrle291e6132011-07-24 20:14:13 +0200116/* Compute the number of octets from the number of septets, for instance: 47 septets needs 41,125 = 42 octets */
117uint8_t gsm_get_octet_len(const uint8_t sept_len){
118 int octet_len = (sept_len * 7) / 8;
119 if ((sept_len * 7) % 8 != 0)
120 octet_len++;
121
122 return octet_len;
123}
124
Nico Golde28de0532010-07-09 17:19:12 +0200125/* GSM 03.38 6.2.1 Character unpacking */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200126int 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 +0100127{
128 int i = 0;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200129 int shift = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200130 uint8_t c7, c8;
Nico Goldec56a56d2012-09-18 14:29:40 +0200131 uint8_t next_is_ext = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200132 const char *text_buf_begin = text;
133 const char *text_buf_end = text + n;
134 int nchars;
135
136 OSMO_ASSERT (n > 0);
Harald Welteec8b4502010-02-20 20:34:29 +0100137
Dennis Wehrle291e6132011-07-24 20:14:13 +0200138 /* skip the user data header */
139 if (ud_hdr_ind) {
140 /* get user data header length + 1 (for the 'user data header length'-field) */
141 shift = ((user_data[0] + 1) * 8) / 7;
142 if ((((user_data[0] + 1) * 8) % 7) != 0)
143 shift++;
144 septet_l = septet_l - shift;
145 }
146
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200147 for (i = 0; i < septet_l && text != text_buf_end - 1; i++) {
148 c7 =
Dennis Wehrle291e6132011-07-24 20:14:13 +0200149 ((user_data[((i + shift) * 7 + 7) >> 3] <<
150 (7 - (((i + shift) * 7 + 7) & 7))) |
151 (user_data[((i + shift) * 7) >> 3] >>
152 (((i + shift) * 7) & 7))) & 0x7f;
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200153
Harald Weltebe55a8b2012-09-20 10:00:25 +0200154 if (next_is_ext) {
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200155 /* this is an extension character */
Nico Goldec56a56d2012-09-18 14:29:40 +0200156 next_is_ext = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200157 c8 = gsm_7bit_alphabet[0x7f + c7];
158 } else if (c7 == 0x1b && i + 1 < septet_l) {
159 next_is_ext = 1;
Nico Golde5b67a042012-09-20 16:56:23 +0200160 continue;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200161 } else {
162 c8 = gsm_septet_lookup(c7);
Nico Golde5b67a042012-09-20 16:56:23 +0200163 }
164
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200165 *(text++) = c8;
Harald Welteec8b4502010-02-20 20:34:29 +0100166 }
167
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200168 nchars = text - text_buf_begin;
169
Nico Golde28de0532010-07-09 17:19:12 +0200170 *text = '\0';
Nico Golde28de0532010-07-09 17:19:12 +0200171
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200172 return nchars;
Nico Golde28de0532010-07-09 17:19:12 +0200173}
174
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200175int 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 +0200176{
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200177 return gsm_7bit_decode_n_hdr(text, n, user_data, septet_l, 0);
Dennis Wehrle291e6132011-07-24 20:14:13 +0200178}
179
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200180int 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 +0200181{
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200182 int nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +0200183
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200184 nchars = gsm_7bit_decode_n_hdr(text, n, user_data, length, 0);
Andreas Eversberg95975552013-08-08 12:38:53 +0200185 /* remove last <CR>, if it fits up to the end of last octet */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200186 if (nchars && (user_data[gsm_get_octet_len(length) - 1] >> 1) == '\r')
187 text[--nchars] = '\0';
Andreas Eversberg95975552013-08-08 12:38:53 +0200188
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200189 return nchars;
Andreas Eversberg95975552013-08-08 12:38:53 +0200190}
191
Nico Golde28de0532010-07-09 17:19:12 +0200192/* GSM 03.38 6.2.1 Prepare character packing */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200193int gsm_septet_encode(uint8_t *result, const char *data)
Nico Golde28de0532010-07-09 17:19:12 +0200194{
195 int i, y = 0;
196 uint8_t ch;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200197 for (i = 0; i < strlen(data); i++) {
Nico Golde28de0532010-07-09 17:19:12 +0200198 ch = data[i];
199 switch(ch){
200 /* fall-through for extension characters */
201 case 0x0c:
202 case 0x5e:
203 case 0x7b:
204 case 0x7d:
205 case 0x5c:
206 case 0x5b:
207 case 0x7e:
208 case 0x5d:
209 case 0x7c:
210 result[y++] = 0x1b;
211 default:
212 result[y] = gsm_7bit_alphabet[ch];
213 break;
214 }
215 y++;
216 }
217
218 return y;
219}
220
Dennis Wehrle291e6132011-07-24 20:14:13 +0200221/* 7bit to octet packing */
Harald Welteca693882013-03-13 15:10:55 +0100222int gsm_septets2octets(uint8_t *result, const uint8_t *rdata, uint8_t septet_len, uint8_t padding)
223{
Dennis Wehrle291e6132011-07-24 20:14:13 +0200224 int i = 0, z = 0;
Nico Golde28de0532010-07-09 17:19:12 +0200225 uint8_t cb, nb;
226 int shift = 0;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200227 uint8_t *data = calloc(septet_len + 1, sizeof(uint8_t));
Nico Golde28de0532010-07-09 17:19:12 +0200228
Dennis Wehrle291e6132011-07-24 20:14:13 +0200229 if (padding) {
230 shift = 7 - padding;
231 /* the first zero is needed for padding */
232 memcpy(data + 1, rdata, septet_len);
233 septet_len++;
234 } else
235 memcpy(data, rdata, septet_len);
Nico Golde28de0532010-07-09 17:19:12 +0200236
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200237 for (i = 0; i < septet_len; i++) {
Dennis Wehrle291e6132011-07-24 20:14:13 +0200238 if (shift == 7) {
239 /*
240 * special end case with the. This is necessary if the
241 * last septet fits into the previous octet. E.g. 48
242 * non-extension characters:
243 * ....ag ( a = 1100001, g = 1100111)
244 * result[40] = 100001 XX, result[41] = 1100111 1 */
245 if (i + 1 < septet_len) {
246 shift = 0;
247 continue;
248 } else if (i + 1 == septet_len)
249 break;
Nico Golde28de0532010-07-09 17:19:12 +0200250 }
251
Dennis Wehrle291e6132011-07-24 20:14:13 +0200252 cb = (data[i] & 0x7f) >> shift;
253 if (i + 1 < septet_len) {
254 nb = (data[i + 1] & 0x7f) << (7 - shift);
Nico Golde28de0532010-07-09 17:19:12 +0200255 cb = cb | nb;
256 }
257
258 result[z++] = cb;
Nico Golde28de0532010-07-09 17:19:12 +0200259 shift++;
260 }
261
Dennis Wehrle291e6132011-07-24 20:14:13 +0200262 free(data);
263
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200264 return z;
Harald Welteec8b4502010-02-20 20:34:29 +0100265}
266
Dennis Wehrle291e6132011-07-24 20:14:13 +0200267/* GSM 03.38 6.2.1 Character packing */
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200268int gsm_7bit_encode_n(uint8_t *result, size_t n, const char *data, int *octets)
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +0200269{
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200270 int y = 0;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200271 int o;
272 int max_septets = n * 8 / 7;
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200273
Dennis Wehrle291e6132011-07-24 20:14:13 +0200274 /* prepare for the worst case, every character expanding to two bytes */
275 uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
276 y = gsm_septet_encode(rdata, data);
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200277
278 if (y > max_septets) {
279 /*
280 * Limit the number of septets to avoid the generation
281 * of more than n octets.
282 */
283 y = max_septets;
284 }
285
286 o = gsm_septets2octets(result, rdata, y, 0);
287
288 if (octets)
289 *octets = o;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200290
291 free(rdata);
292
293 /*
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200294 * We don't care about the number of octets, because they are not
Dennis Wehrle291e6132011-07-24 20:14:13 +0200295 * unique. E.g.:
296 * 1.) 46 non-extension characters + 1 extension character
297 * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets
298 * 2.) 47 non-extension characters
299 * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets
300 * 3.) 48 non-extension characters
301 * => (48 * 7 bit) / 8 bit = 42 octects
302 */
303 return y;
304}
305
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200306int gsm_7bit_encode_n_ussd(uint8_t *result, size_t n, const char *data, int *octets)
307{
308 int y;
309
310 y = gsm_7bit_encode_n(result, n, data, octets);
311 /* if last octet contains only one bit, add <CR> */
312 if (((y * 7) & 7) == 1)
313 result[(*octets) - 1] |= ('\r' << 1);
314 /* if last character is <CR> and completely fills last octet, add
315 * another <CR>. */
316 if (y && ((y * 7) & 7) == 0 && (result[(*octets) - 1] >> 1) == '\r' && *octets < n - 1) {
317 result[(*octets)++] = '\r';
318 y++;
319 }
320
321 return y;
322}
323
Andreas Eversberg2a68c7c2011-06-26 11:41:48 +0200324/* convert power class to dBm according to GSM TS 05.05 */
325unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class)
326{
327 switch (band) {
328 case GSM_BAND_450:
329 case GSM_BAND_480:
330 case GSM_BAND_750:
331 case GSM_BAND_900:
332 case GSM_BAND_810:
333 case GSM_BAND_850:
334 if (class == 1)
335 return 43; /* 20W */
336 if (class == 2)
337 return 39; /* 8W */
338 if (class == 3)
339 return 37; /* 5W */
340 if (class == 4)
341 return 33; /* 2W */
342 if (class == 5)
343 return 29; /* 0.8W */
344 break;
345 case GSM_BAND_1800:
346 if (class == 1)
347 return 30; /* 1W */
348 if (class == 2)
349 return 24; /* 0.25W */
350 if (class == 3)
351 return 36; /* 4W */
352 break;
353 case GSM_BAND_1900:
354 if (class == 1)
355 return 30; /* 1W */
356 if (class == 2)
357 return 24; /* 0.25W */
358 if (class == 3)
359 return 33; /* 2W */
360 break;
361 }
362 return -EINVAL;
363}
364
Harald Welteec8b4502010-02-20 20:34:29 +0100365/* determine power control level for given dBm value, as indicated
366 * by the tables in chapter 4.1.1 of GSM TS 05.05 */
367int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
368{
369 switch (band) {
370 case GSM_BAND_450:
371 case GSM_BAND_480:
372 case GSM_BAND_750:
373 case GSM_BAND_900:
374 case GSM_BAND_810:
375 case GSM_BAND_850:
376 if (dbm >= 39)
377 return 0;
378 else if (dbm < 5)
379 return 19;
380 else {
381 /* we are guaranteed to have (5 <= dbm < 39) */
382 return 2 + ((39 - dbm) / 2);
383 }
384 break;
385 case GSM_BAND_1800:
386 if (dbm >= 36)
387 return 29;
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200388 else if (dbm >= 34)
Harald Welteec8b4502010-02-20 20:34:29 +0100389 return 30;
390 else if (dbm >= 32)
391 return 31;
392 else if (dbm == 31)
393 return 0;
394 else {
395 /* we are guaranteed to have (0 <= dbm < 31) */
396 return (30 - dbm) / 2;
397 }
398 break;
399 case GSM_BAND_1900:
400 if (dbm >= 33)
401 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 }
412 return -EINVAL;
413}
414
415int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
416{
417 lvl &= 0x1f;
418
419 switch (band) {
420 case GSM_BAND_450:
421 case GSM_BAND_480:
422 case GSM_BAND_750:
423 case GSM_BAND_900:
424 case GSM_BAND_810:
425 case GSM_BAND_850:
426 if (lvl < 2)
427 return 39;
428 else if (lvl < 20)
429 return 39 - ((lvl - 2) * 2) ;
430 else
431 return 5;
432 break;
433 case GSM_BAND_1800:
434 if (lvl < 16)
435 return 30 - (lvl * 2);
436 else if (lvl < 29)
437 return 0;
438 else
439 return 36 - ((lvl - 29) * 2);
440 break;
441 case GSM_BAND_1900:
442 if (lvl < 16)
443 return 30 - (lvl * 2);
444 else if (lvl < 30)
445 return -EINVAL;
446 else
447 return 33 - (lvl - 30);
448 break;
449 }
450 return -EINVAL;
451}
452
Bhaskar6b30f922013-05-16 17:35:49 +0530453/* According to TS 05.08 Chapter 8.1.4 */
Harald Welteec8b4502010-02-20 20:34:29 +0100454int rxlev2dbm(uint8_t rxlev)
455{
456 if (rxlev > 63)
457 rxlev = 63;
458
459 return -110 + rxlev;
460}
461
Bhaskar6b30f922013-05-16 17:35:49 +0530462/* According to TS 05.08 Chapter 8.1.4 */
Harald Welteec8b4502010-02-20 20:34:29 +0100463uint8_t dbm2rxlev(int dbm)
464{
465 int rxlev = dbm + 110;
466
467 if (rxlev > 63)
468 rxlev = 63;
469 else if (rxlev < 0)
470 rxlev = 0;
471
472 return rxlev;
473}
474
Harald Weltecbc80622010-03-22 08:28:44 +0800475const char *gsm_band_name(enum gsm_band band)
Harald Welteaebe08c2010-03-04 10:39:17 +0100476{
477 switch (band) {
478 case GSM_BAND_450:
479 return "GSM450";
480 case GSM_BAND_480:
Sylvain Munaute10ae5b2010-07-04 11:41:36 +0200481 return "GSM480";
Harald Welteaebe08c2010-03-04 10:39:17 +0100482 case GSM_BAND_750:
483 return "GSM750";
484 case GSM_BAND_810:
485 return "GSM810";
486 case GSM_BAND_850:
487 return "GSM850";
488 case GSM_BAND_900:
489 return "GSM900";
490 case GSM_BAND_1800:
491 return "DCS1800";
492 case GSM_BAND_1900:
493 return "PCS1900";
494 }
495 return "invalid";
496}
497
498enum gsm_band gsm_band_parse(const char* mhz)
499{
500 while (*mhz && !isdigit(*mhz))
501 mhz++;
502
503 if (*mhz == '\0')
504 return -EINVAL;
505
Harald Welted3ff15f2010-03-07 18:23:47 +0100506 switch (strtol(mhz, NULL, 10)) {
Harald Welteaebe08c2010-03-04 10:39:17 +0100507 case 450:
508 return GSM_BAND_450;
509 case 480:
510 return GSM_BAND_480;
511 case 750:
512 return GSM_BAND_750;
513 case 810:
514 return GSM_BAND_810;
515 case 850:
516 return GSM_BAND_850;
517 case 900:
518 return GSM_BAND_900;
519 case 1800:
520 return GSM_BAND_1800;
521 case 1900:
522 return GSM_BAND_1900;
523 default:
524 return -EINVAL;
525 }
526}
527
Harald Welte622b7182010-03-07 17:50:21 +0100528enum gsm_band gsm_arfcn2band(uint16_t arfcn)
529{
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100530 int is_pcs = arfcn & ARFCN_PCS;
531
532 arfcn &= ~ARFCN_FLAG_MASK;
533
534 if (is_pcs)
Harald Welte622b7182010-03-07 17:50:21 +0100535 return GSM_BAND_1900;
536 else if (arfcn <= 124)
537 return GSM_BAND_900;
538 else if (arfcn >= 955 && arfcn <= 1023)
539 return GSM_BAND_900;
540 else if (arfcn >= 128 && arfcn <= 251)
541 return GSM_BAND_850;
542 else if (arfcn >= 512 && arfcn <= 885)
543 return GSM_BAND_1800;
544 else if (arfcn >= 259 && arfcn <= 293)
545 return GSM_BAND_450;
546 else if (arfcn >= 306 && arfcn <= 340)
547 return GSM_BAND_480;
548 else if (arfcn >= 350 && arfcn <= 425)
549 return GSM_BAND_810;
550 else if (arfcn >= 438 && arfcn <= 511)
551 return GSM_BAND_750;
552 else
553 return GSM_BAND_1800;
554}
555
Sylvain Munaut55720312012-12-11 23:44:41 +0100556struct gsm_freq_range {
557 uint16_t arfcn_first;
558 uint16_t arfcn_last;
559 uint16_t freq_ul_first;
560 uint16_t freq_dl_offset;
561 uint16_t flags;
562};
563
564static struct gsm_freq_range gsm_ranges[] = {
565 { 512, 810, 18502, 800, ARFCN_PCS }, /* PCS 1900 */
566 { 0, 124, 8900, 450, 0 }, /* P-GSM + E-GSM ARFCN 0 */
567 { 955, 1023, 8762, 450, 0 }, /* E-GSM + R-GSM */
568 { 128, 251, 8242, 450, 0 }, /* GSM 850 */
569 { 512, 885, 17102, 950, 0 }, /* DCS 1800 */
570 { 259, 293, 4506, 100, 0 }, /* GSM 450 */
571 { 306, 340, 4790, 100, 0 }, /* GSM 480 */
572 { 350, 425, 8060, 450, 0 }, /* GSM 810 */
573 { 438, 511, 7472, 300, 0 }, /* GSM 750 */
574 { /* Guard */ }
575};
576
Harald Welte622b7182010-03-07 17:50:21 +0100577/* Convert an ARFCN to the frequency in MHz * 10 */
578uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
579{
Sylvain Munaut55720312012-12-11 23:44:41 +0100580 struct gsm_freq_range *r;
581 uint16_t flags = arfcn & ARFCN_FLAG_MASK;
582 uint16_t freq10_ul = 0xffff;
583 uint16_t freq10_dl = 0xffff;
Harald Welte622b7182010-03-07 17:50:21 +0100584
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100585 arfcn &= ~ARFCN_FLAG_MASK;
586
Sylvain Munaut55720312012-12-11 23:44:41 +0100587 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
588 if ((flags == r->flags) &&
589 (arfcn >= r->arfcn_first) &&
590 (arfcn <= r->arfcn_last))
591 {
592 freq10_ul = r->freq_ul_first + 2 * (arfcn - r->arfcn_first);
593 freq10_dl = freq10_ul + r->freq_dl_offset;
594 break;
595 }
596 }
597
598 return uplink ? freq10_ul : freq10_dl;
599}
600
601/* Convert a Frequency in MHz * 10 to ARFCN */
602uint16_t gsm_freq102arfcn(uint16_t freq10, int uplink)
603{
604 struct gsm_freq_range *r;
605 uint16_t freq10_lo, freq10_hi;
606 uint16_t arfcn = 0xffff;
607
608 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
609 /* Generate frequency limits */
610 freq10_lo = r->freq_ul_first;
611 freq10_hi = freq10_lo + 2 * (r->arfcn_last - r->arfcn_first);
612 if (!uplink) {
613 freq10_lo += r->freq_dl_offset;
614 freq10_hi += r->freq_dl_offset;
615 }
616
617 /* Check if this fits */
618 if (freq10 >= freq10_lo && freq10 <= freq10_hi) {
619 arfcn = r->arfcn_first + ((freq10 - freq10_lo) >> 1);
620 arfcn |= r->flags;
621 break;
622 }
623 }
Harald Welte622b7182010-03-07 17:50:21 +0100624
625 if (uplink)
Sylvain Munaut55720312012-12-11 23:44:41 +0100626 arfcn |= ARFCN_UPLINK;
627
628 return arfcn;
Harald Welte622b7182010-03-07 17:50:21 +0100629}
630
631void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
632{
633 time->fn = fn;
634 time->t1 = time->fn / (26*51);
635 time->t2 = time->fn % 26;
636 time->t3 = time->fn % 51;
637 time->tc = (time->fn / 51) % 8;
638}
639
640uint32_t gsm_gsmtime2fn(struct gsm_time *time)
641{
642 /* TS 05.02 Chapter 4.3.3 TDMA frame number */
643 return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
644}
Harald Weltea1c4f762010-05-01 11:59:42 +0200645
646/* TS 03.03 Chapter 2.6 */
647int gprs_tlli_type(uint32_t tlli)
648{
649 if ((tlli & 0xc0000000) == 0xc0000000)
650 return TLLI_LOCAL;
651 else if ((tlli & 0xc0000000) == 0x80000000)
652 return TLLI_FOREIGN;
653 else if ((tlli & 0xf8000000) == 0x78000000)
654 return TLLI_RANDOM;
655 else if ((tlli & 0xf8000000) == 0x70000000)
656 return TLLI_AUXILIARY;
657
658 return TLLI_RESERVED;
659}
Harald Weltec2263172010-06-01 10:47:07 +0200660
661uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
662{
663 uint32_t tlli;
664 switch (type) {
665 case TLLI_LOCAL:
666 tlli = p_tmsi | 0xc0000000;
667 break;
668 case TLLI_FOREIGN:
669 tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
670 break;
671 default:
672 tlli = 0;
673 break;
674 }
675 return tlli;
676}
Jacob Erlbeck1d7f3b52013-08-12 17:07:53 +0200677
678/* Wrappers for deprecated functions: */
679
680int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l)
681{
682 gsm_7bit_decode_n(text, SIZE_MAX, user_data, septet_l);
683
684 /* Mimic the original behaviour. */
685 return septet_l;
686}
687
688int gsm_7bit_decode_ussd(char *text, const uint8_t *user_data, uint8_t length)
689{
690 return gsm_7bit_decode_n_ussd(text, SIZE_MAX, user_data, length);
691}
692
693int gsm_7bit_encode(uint8_t *result, const char *data)
694{
695 int out;
696 return gsm_7bit_encode_n(result, SIZE_MAX, data, &out);
697}
698
699int gsm_7bit_encode_ussd(uint8_t *result, const char *data, int *octets)
700{
701 return gsm_7bit_encode_n_ussd(result, SIZE_MAX, data, octets);
702}
703
704int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets)
705{
706 return gsm_7bit_encode_n(result, SIZE_MAX, data, octets);
707}