blob: 54b965e29c072246b9dc5949173d2829bf6db4c5 [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,
31 * a GSM TLV parser, SMS utility routines as well as
32 * 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 */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200126int gsm_7bit_decode_hdr(char *text, 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;
Nico Goldec56a56d2012-09-18 14:29:40 +0200130 uint8_t c;
131 uint8_t next_is_ext = 0;
Harald Welteec8b4502010-02-20 20:34:29 +0100132
Dennis Wehrle291e6132011-07-24 20:14:13 +0200133 /* skip the user data header */
134 if (ud_hdr_ind) {
135 /* get user data header length + 1 (for the 'user data header length'-field) */
136 shift = ((user_data[0] + 1) * 8) / 7;
137 if ((((user_data[0] + 1) * 8) % 7) != 0)
138 shift++;
139 septet_l = septet_l - shift;
140 }
141
142 for (i = 0; i < septet_l; i++) {
Nico Goldec56a56d2012-09-18 14:29:40 +0200143 c =
Dennis Wehrle291e6132011-07-24 20:14:13 +0200144 ((user_data[((i + shift) * 7 + 7) >> 3] <<
145 (7 - (((i + shift) * 7 + 7) & 7))) |
146 (user_data[((i + shift) * 7) >> 3] >>
147 (((i + shift) * 7) & 7))) & 0x7f;
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200148
Nico Goldec56a56d2012-09-18 14:29:40 +0200149 /* this is an extension character */
Harald Weltebe55a8b2012-09-20 10:00:25 +0200150 if (next_is_ext) {
Nico Goldec56a56d2012-09-18 14:29:40 +0200151 next_is_ext = 0;
152 *(text++) = gsm_7bit_alphabet[0x7f + c];
Nico Golde5b67a042012-09-20 16:56:23 +0200153 continue;
154 }
155
156 if (c == 0x1b && i + 1 < septet_l) {
157 next_is_ext = 1;
Nico Goldec56a56d2012-09-18 14:29:40 +0200158 } else {
159 *(text++) = gsm_septet_lookup(c);
160 }
Harald Welteec8b4502010-02-20 20:34:29 +0100161 }
162
Dennis Wehrle291e6132011-07-24 20:14:13 +0200163 if (ud_hdr_ind)
164 i += shift;
Nico Golde28de0532010-07-09 17:19:12 +0200165 *text = '\0';
Nico Golde28de0532010-07-09 17:19:12 +0200166
167 return i;
168}
169
Dennis Wehrle291e6132011-07-24 20:14:13 +0200170int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l)
171{
172 return gsm_7bit_decode_hdr(text, user_data, septet_l, 0);
173}
174
Nico Golde28de0532010-07-09 17:19:12 +0200175/* GSM 03.38 6.2.1 Prepare character packing */
Dennis Wehrle291e6132011-07-24 20:14:13 +0200176int gsm_septet_encode(uint8_t *result, const char *data)
Nico Golde28de0532010-07-09 17:19:12 +0200177{
178 int i, y = 0;
179 uint8_t ch;
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200180 for (i = 0; i < strlen(data); i++) {
Nico Golde28de0532010-07-09 17:19:12 +0200181 ch = data[i];
182 switch(ch){
183 /* fall-through for extension characters */
184 case 0x0c:
185 case 0x5e:
186 case 0x7b:
187 case 0x7d:
188 case 0x5c:
189 case 0x5b:
190 case 0x7e:
191 case 0x5d:
192 case 0x7c:
193 result[y++] = 0x1b;
194 default:
195 result[y] = gsm_7bit_alphabet[ch];
196 break;
197 }
198 y++;
199 }
200
201 return y;
202}
203
Dennis Wehrle291e6132011-07-24 20:14:13 +0200204/* 7bit to octet packing */
Harald Welteca693882013-03-13 15:10:55 +0100205int gsm_septets2octets(uint8_t *result, const uint8_t *rdata, uint8_t septet_len, uint8_t padding)
206{
Dennis Wehrle291e6132011-07-24 20:14:13 +0200207 int i = 0, z = 0;
Nico Golde28de0532010-07-09 17:19:12 +0200208 uint8_t cb, nb;
209 int shift = 0;
Dennis Wehrle291e6132011-07-24 20:14:13 +0200210 uint8_t *data = calloc(septet_len + 1, sizeof(uint8_t));
Nico Golde28de0532010-07-09 17:19:12 +0200211
Dennis Wehrle291e6132011-07-24 20:14:13 +0200212 if (padding) {
213 shift = 7 - padding;
214 /* the first zero is needed for padding */
215 memcpy(data + 1, rdata, septet_len);
216 septet_len++;
217 } else
218 memcpy(data, rdata, septet_len);
Nico Golde28de0532010-07-09 17:19:12 +0200219
Holger Hans Peter Freyther7e1a6222011-07-24 20:17:00 +0200220 for (i = 0; i < septet_len; i++) {
Dennis Wehrle291e6132011-07-24 20:14:13 +0200221 if (shift == 7) {
222 /*
223 * special end case with the. This is necessary if the
224 * last septet fits into the previous octet. E.g. 48
225 * non-extension characters:
226 * ....ag ( a = 1100001, g = 1100111)
227 * result[40] = 100001 XX, result[41] = 1100111 1 */
228 if (i + 1 < septet_len) {
229 shift = 0;
230 continue;
231 } else if (i + 1 == septet_len)
232 break;
Nico Golde28de0532010-07-09 17:19:12 +0200233 }
234
Dennis Wehrle291e6132011-07-24 20:14:13 +0200235 cb = (data[i] & 0x7f) >> shift;
236 if (i + 1 < septet_len) {
237 nb = (data[i + 1] & 0x7f) << (7 - shift);
Nico Golde28de0532010-07-09 17:19:12 +0200238 cb = cb | nb;
239 }
240
241 result[z++] = cb;
Nico Golde28de0532010-07-09 17:19:12 +0200242 shift++;
243 }
244
Dennis Wehrle291e6132011-07-24 20:14:13 +0200245 free(data);
246
Nico Goldec0ce9aa2010-07-20 15:43:58 +0200247 return z;
Harald Welteec8b4502010-02-20 20:34:29 +0100248}
249
Dennis Wehrle291e6132011-07-24 20:14:13 +0200250/* GSM 03.38 6.2.1 Character packing */
251int gsm_7bit_encode(uint8_t *result, const char *data)
252{
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +0200253 int out;
254 return gsm_7bit_encode_oct(result, data, &out);
255}
256
257int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets)
258{
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200259 int y = 0;
260
Dennis Wehrle291e6132011-07-24 20:14:13 +0200261 /* prepare for the worst case, every character expanding to two bytes */
262 uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
263 y = gsm_septet_encode(rdata, data);
Holger Hans Peter Freyther6bfa7442013-08-08 12:38:52 +0200264 *octets = gsm_septets2octets(result, rdata, y, 0);
Dennis Wehrle291e6132011-07-24 20:14:13 +0200265
266 free(rdata);
267
268 /*
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200269 * We don't care about the number of octets, because they are not
Dennis Wehrle291e6132011-07-24 20:14:13 +0200270 * unique. E.g.:
271 * 1.) 46 non-extension characters + 1 extension character
272 * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets
273 * 2.) 47 non-extension characters
274 * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets
275 * 3.) 48 non-extension characters
276 * => (48 * 7 bit) / 8 bit = 42 octects
277 */
278 return y;
279}
280
Andreas Eversberg2a68c7c2011-06-26 11:41:48 +0200281/* convert power class to dBm according to GSM TS 05.05 */
282unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class)
283{
284 switch (band) {
285 case GSM_BAND_450:
286 case GSM_BAND_480:
287 case GSM_BAND_750:
288 case GSM_BAND_900:
289 case GSM_BAND_810:
290 case GSM_BAND_850:
291 if (class == 1)
292 return 43; /* 20W */
293 if (class == 2)
294 return 39; /* 8W */
295 if (class == 3)
296 return 37; /* 5W */
297 if (class == 4)
298 return 33; /* 2W */
299 if (class == 5)
300 return 29; /* 0.8W */
301 break;
302 case GSM_BAND_1800:
303 if (class == 1)
304 return 30; /* 1W */
305 if (class == 2)
306 return 24; /* 0.25W */
307 if (class == 3)
308 return 36; /* 4W */
309 break;
310 case GSM_BAND_1900:
311 if (class == 1)
312 return 30; /* 1W */
313 if (class == 2)
314 return 24; /* 0.25W */
315 if (class == 3)
316 return 33; /* 2W */
317 break;
318 }
319 return -EINVAL;
320}
321
Harald Welteec8b4502010-02-20 20:34:29 +0100322/* determine power control level for given dBm value, as indicated
323 * by the tables in chapter 4.1.1 of GSM TS 05.05 */
324int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
325{
326 switch (band) {
327 case GSM_BAND_450:
328 case GSM_BAND_480:
329 case GSM_BAND_750:
330 case GSM_BAND_900:
331 case GSM_BAND_810:
332 case GSM_BAND_850:
333 if (dbm >= 39)
334 return 0;
335 else if (dbm < 5)
336 return 19;
337 else {
338 /* we are guaranteed to have (5 <= dbm < 39) */
339 return 2 + ((39 - dbm) / 2);
340 }
341 break;
342 case GSM_BAND_1800:
343 if (dbm >= 36)
344 return 29;
345 else if (dbm >= 34)
346 return 30;
347 else if (dbm >= 32)
348 return 31;
349 else if (dbm == 31)
350 return 0;
351 else {
352 /* we are guaranteed to have (0 <= dbm < 31) */
353 return (30 - dbm) / 2;
354 }
355 break;
356 case GSM_BAND_1900:
357 if (dbm >= 33)
358 return 30;
359 else if (dbm >= 32)
360 return 31;
361 else if (dbm == 31)
362 return 0;
363 else {
364 /* we are guaranteed to have (0 <= dbm < 31) */
365 return (30 - dbm) / 2;
366 }
367 break;
368 }
369 return -EINVAL;
370}
371
372int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
373{
374 lvl &= 0x1f;
375
376 switch (band) {
377 case GSM_BAND_450:
378 case GSM_BAND_480:
379 case GSM_BAND_750:
380 case GSM_BAND_900:
381 case GSM_BAND_810:
382 case GSM_BAND_850:
383 if (lvl < 2)
384 return 39;
385 else if (lvl < 20)
386 return 39 - ((lvl - 2) * 2) ;
387 else
388 return 5;
389 break;
390 case GSM_BAND_1800:
391 if (lvl < 16)
392 return 30 - (lvl * 2);
393 else if (lvl < 29)
394 return 0;
395 else
396 return 36 - ((lvl - 29) * 2);
397 break;
398 case GSM_BAND_1900:
399 if (lvl < 16)
400 return 30 - (lvl * 2);
401 else if (lvl < 30)
402 return -EINVAL;
403 else
404 return 33 - (lvl - 30);
405 break;
406 }
407 return -EINVAL;
408}
409
Bhaskar6b30f922013-05-16 17:35:49 +0530410/* According to TS 05.08 Chapter 8.1.4 */
Harald Welteec8b4502010-02-20 20:34:29 +0100411int rxlev2dbm(uint8_t rxlev)
412{
413 if (rxlev > 63)
414 rxlev = 63;
415
416 return -110 + rxlev;
417}
418
Bhaskar6b30f922013-05-16 17:35:49 +0530419/* According to TS 05.08 Chapter 8.1.4 */
Harald Welteec8b4502010-02-20 20:34:29 +0100420uint8_t dbm2rxlev(int dbm)
421{
422 int rxlev = dbm + 110;
423
424 if (rxlev > 63)
425 rxlev = 63;
426 else if (rxlev < 0)
427 rxlev = 0;
428
429 return rxlev;
430}
431
Harald Weltecbc80622010-03-22 08:28:44 +0800432const char *gsm_band_name(enum gsm_band band)
Harald Welteaebe08c2010-03-04 10:39:17 +0100433{
434 switch (band) {
435 case GSM_BAND_450:
436 return "GSM450";
437 case GSM_BAND_480:
Sylvain Munaute10ae5b2010-07-04 11:41:36 +0200438 return "GSM480";
Harald Welteaebe08c2010-03-04 10:39:17 +0100439 case GSM_BAND_750:
440 return "GSM750";
441 case GSM_BAND_810:
442 return "GSM810";
443 case GSM_BAND_850:
444 return "GSM850";
445 case GSM_BAND_900:
446 return "GSM900";
447 case GSM_BAND_1800:
448 return "DCS1800";
449 case GSM_BAND_1900:
450 return "PCS1900";
451 }
452 return "invalid";
453}
454
455enum gsm_band gsm_band_parse(const char* mhz)
456{
457 while (*mhz && !isdigit(*mhz))
458 mhz++;
459
460 if (*mhz == '\0')
461 return -EINVAL;
462
Harald Welted3ff15f2010-03-07 18:23:47 +0100463 switch (strtol(mhz, NULL, 10)) {
Harald Welteaebe08c2010-03-04 10:39:17 +0100464 case 450:
465 return GSM_BAND_450;
466 case 480:
467 return GSM_BAND_480;
468 case 750:
469 return GSM_BAND_750;
470 case 810:
471 return GSM_BAND_810;
472 case 850:
473 return GSM_BAND_850;
474 case 900:
475 return GSM_BAND_900;
476 case 1800:
477 return GSM_BAND_1800;
478 case 1900:
479 return GSM_BAND_1900;
480 default:
481 return -EINVAL;
482 }
483}
484
Harald Welte622b7182010-03-07 17:50:21 +0100485enum gsm_band gsm_arfcn2band(uint16_t arfcn)
486{
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100487 int is_pcs = arfcn & ARFCN_PCS;
488
489 arfcn &= ~ARFCN_FLAG_MASK;
490
491 if (is_pcs)
Harald Welte622b7182010-03-07 17:50:21 +0100492 return GSM_BAND_1900;
493 else if (arfcn <= 124)
494 return GSM_BAND_900;
495 else if (arfcn >= 955 && arfcn <= 1023)
496 return GSM_BAND_900;
497 else if (arfcn >= 128 && arfcn <= 251)
498 return GSM_BAND_850;
499 else if (arfcn >= 512 && arfcn <= 885)
500 return GSM_BAND_1800;
501 else if (arfcn >= 259 && arfcn <= 293)
502 return GSM_BAND_450;
503 else if (arfcn >= 306 && arfcn <= 340)
504 return GSM_BAND_480;
505 else if (arfcn >= 350 && arfcn <= 425)
506 return GSM_BAND_810;
507 else if (arfcn >= 438 && arfcn <= 511)
508 return GSM_BAND_750;
509 else
510 return GSM_BAND_1800;
511}
512
Sylvain Munaut55720312012-12-11 23:44:41 +0100513struct gsm_freq_range {
514 uint16_t arfcn_first;
515 uint16_t arfcn_last;
516 uint16_t freq_ul_first;
517 uint16_t freq_dl_offset;
518 uint16_t flags;
519};
520
521static struct gsm_freq_range gsm_ranges[] = {
522 { 512, 810, 18502, 800, ARFCN_PCS }, /* PCS 1900 */
523 { 0, 124, 8900, 450, 0 }, /* P-GSM + E-GSM ARFCN 0 */
524 { 955, 1023, 8762, 450, 0 }, /* E-GSM + R-GSM */
525 { 128, 251, 8242, 450, 0 }, /* GSM 850 */
526 { 512, 885, 17102, 950, 0 }, /* DCS 1800 */
527 { 259, 293, 4506, 100, 0 }, /* GSM 450 */
528 { 306, 340, 4790, 100, 0 }, /* GSM 480 */
529 { 350, 425, 8060, 450, 0 }, /* GSM 810 */
530 { 438, 511, 7472, 300, 0 }, /* GSM 750 */
531 { /* Guard */ }
532};
533
Harald Welte622b7182010-03-07 17:50:21 +0100534/* Convert an ARFCN to the frequency in MHz * 10 */
535uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
536{
Sylvain Munaut55720312012-12-11 23:44:41 +0100537 struct gsm_freq_range *r;
538 uint16_t flags = arfcn & ARFCN_FLAG_MASK;
539 uint16_t freq10_ul = 0xffff;
540 uint16_t freq10_dl = 0xffff;
Harald Welte622b7182010-03-07 17:50:21 +0100541
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100542 arfcn &= ~ARFCN_FLAG_MASK;
543
Sylvain Munaut55720312012-12-11 23:44:41 +0100544 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
545 if ((flags == r->flags) &&
546 (arfcn >= r->arfcn_first) &&
547 (arfcn <= r->arfcn_last))
548 {
549 freq10_ul = r->freq_ul_first + 2 * (arfcn - r->arfcn_first);
550 freq10_dl = freq10_ul + r->freq_dl_offset;
551 break;
552 }
553 }
554
555 return uplink ? freq10_ul : freq10_dl;
556}
557
558/* Convert a Frequency in MHz * 10 to ARFCN */
559uint16_t gsm_freq102arfcn(uint16_t freq10, int uplink)
560{
561 struct gsm_freq_range *r;
562 uint16_t freq10_lo, freq10_hi;
563 uint16_t arfcn = 0xffff;
564
565 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
566 /* Generate frequency limits */
567 freq10_lo = r->freq_ul_first;
568 freq10_hi = freq10_lo + 2 * (r->arfcn_last - r->arfcn_first);
569 if (!uplink) {
570 freq10_lo += r->freq_dl_offset;
571 freq10_hi += r->freq_dl_offset;
572 }
573
574 /* Check if this fits */
575 if (freq10 >= freq10_lo && freq10 <= freq10_hi) {
576 arfcn = r->arfcn_first + ((freq10 - freq10_lo) >> 1);
577 arfcn |= r->flags;
578 break;
579 }
580 }
Harald Welte622b7182010-03-07 17:50:21 +0100581
582 if (uplink)
Sylvain Munaut55720312012-12-11 23:44:41 +0100583 arfcn |= ARFCN_UPLINK;
584
585 return arfcn;
Harald Welte622b7182010-03-07 17:50:21 +0100586}
587
588void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
589{
590 time->fn = fn;
591 time->t1 = time->fn / (26*51);
592 time->t2 = time->fn % 26;
593 time->t3 = time->fn % 51;
594 time->tc = (time->fn / 51) % 8;
595}
596
597uint32_t gsm_gsmtime2fn(struct gsm_time *time)
598{
599 /* TS 05.02 Chapter 4.3.3 TDMA frame number */
600 return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
601}
Harald Weltea1c4f762010-05-01 11:59:42 +0200602
603/* TS 03.03 Chapter 2.6 */
604int gprs_tlli_type(uint32_t tlli)
605{
606 if ((tlli & 0xc0000000) == 0xc0000000)
607 return TLLI_LOCAL;
608 else if ((tlli & 0xc0000000) == 0x80000000)
609 return TLLI_FOREIGN;
610 else if ((tlli & 0xf8000000) == 0x78000000)
611 return TLLI_RANDOM;
612 else if ((tlli & 0xf8000000) == 0x70000000)
613 return TLLI_AUXILIARY;
614
615 return TLLI_RESERVED;
616}
Harald Weltec2263172010-06-01 10:47:07 +0200617
618uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
619{
620 uint32_t tlli;
621 switch (type) {
622 case TLLI_LOCAL:
623 tlli = p_tmsi | 0xc0000000;
624 break;
625 case TLLI_FOREIGN:
626 tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
627 break;
628 default:
629 tlli = 0;
630 break;
631 }
632 return tlli;
633}