blob: 9569cf32f648e39853b6b1e2a98834486e273473 [file] [log] [blame]
Harald Welteec8b4502010-02-20 20:34:29 +01001/*
2 * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
3 * (C) 2009 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 Freythercc7d9ec2012-09-11 10:38:43 +0200253 int y = 0;
254
Dennis Wehrle291e6132011-07-24 20:14:13 +0200255 /* prepare for the worst case, every character expanding to two bytes */
256 uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t));
257 y = gsm_septet_encode(rdata, data);
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200258 gsm_septets2octets(result, rdata, y, 0);
Dennis Wehrle291e6132011-07-24 20:14:13 +0200259
260 free(rdata);
261
262 /*
Holger Hans Peter Freythercc7d9ec2012-09-11 10:38:43 +0200263 * We don't care about the number of octets, because they are not
Dennis Wehrle291e6132011-07-24 20:14:13 +0200264 * unique. E.g.:
265 * 1.) 46 non-extension characters + 1 extension character
266 * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets
267 * 2.) 47 non-extension characters
268 * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets
269 * 3.) 48 non-extension characters
270 * => (48 * 7 bit) / 8 bit = 42 octects
271 */
272 return y;
273}
274
Andreas Eversberg2a68c7c2011-06-26 11:41:48 +0200275/* convert power class to dBm according to GSM TS 05.05 */
276unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class)
277{
278 switch (band) {
279 case GSM_BAND_450:
280 case GSM_BAND_480:
281 case GSM_BAND_750:
282 case GSM_BAND_900:
283 case GSM_BAND_810:
284 case GSM_BAND_850:
285 if (class == 1)
286 return 43; /* 20W */
287 if (class == 2)
288 return 39; /* 8W */
289 if (class == 3)
290 return 37; /* 5W */
291 if (class == 4)
292 return 33; /* 2W */
293 if (class == 5)
294 return 29; /* 0.8W */
295 break;
296 case GSM_BAND_1800:
297 if (class == 1)
298 return 30; /* 1W */
299 if (class == 2)
300 return 24; /* 0.25W */
301 if (class == 3)
302 return 36; /* 4W */
303 break;
304 case GSM_BAND_1900:
305 if (class == 1)
306 return 30; /* 1W */
307 if (class == 2)
308 return 24; /* 0.25W */
309 if (class == 3)
310 return 33; /* 2W */
311 break;
312 }
313 return -EINVAL;
314}
315
Harald Welteec8b4502010-02-20 20:34:29 +0100316/* determine power control level for given dBm value, as indicated
317 * by the tables in chapter 4.1.1 of GSM TS 05.05 */
318int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
319{
320 switch (band) {
321 case GSM_BAND_450:
322 case GSM_BAND_480:
323 case GSM_BAND_750:
324 case GSM_BAND_900:
325 case GSM_BAND_810:
326 case GSM_BAND_850:
327 if (dbm >= 39)
328 return 0;
329 else if (dbm < 5)
330 return 19;
331 else {
332 /* we are guaranteed to have (5 <= dbm < 39) */
333 return 2 + ((39 - dbm) / 2);
334 }
335 break;
336 case GSM_BAND_1800:
337 if (dbm >= 36)
338 return 29;
339 else if (dbm >= 34)
340 return 30;
341 else if (dbm >= 32)
342 return 31;
343 else if (dbm == 31)
344 return 0;
345 else {
346 /* we are guaranteed to have (0 <= dbm < 31) */
347 return (30 - dbm) / 2;
348 }
349 break;
350 case GSM_BAND_1900:
351 if (dbm >= 33)
352 return 30;
353 else if (dbm >= 32)
354 return 31;
355 else if (dbm == 31)
356 return 0;
357 else {
358 /* we are guaranteed to have (0 <= dbm < 31) */
359 return (30 - dbm) / 2;
360 }
361 break;
362 }
363 return -EINVAL;
364}
365
366int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
367{
368 lvl &= 0x1f;
369
370 switch (band) {
371 case GSM_BAND_450:
372 case GSM_BAND_480:
373 case GSM_BAND_750:
374 case GSM_BAND_900:
375 case GSM_BAND_810:
376 case GSM_BAND_850:
377 if (lvl < 2)
378 return 39;
379 else if (lvl < 20)
380 return 39 - ((lvl - 2) * 2) ;
381 else
382 return 5;
383 break;
384 case GSM_BAND_1800:
385 if (lvl < 16)
386 return 30 - (lvl * 2);
387 else if (lvl < 29)
388 return 0;
389 else
390 return 36 - ((lvl - 29) * 2);
391 break;
392 case GSM_BAND_1900:
393 if (lvl < 16)
394 return 30 - (lvl * 2);
395 else if (lvl < 30)
396 return -EINVAL;
397 else
398 return 33 - (lvl - 30);
399 break;
400 }
401 return -EINVAL;
402}
403
Bhaskar6b30f922013-05-16 17:35:49 +0530404/* According to TS 05.08 Chapter 8.1.4 */
Harald Welteec8b4502010-02-20 20:34:29 +0100405int rxlev2dbm(uint8_t rxlev)
406{
407 if (rxlev > 63)
408 rxlev = 63;
409
410 return -110 + rxlev;
411}
412
Bhaskar6b30f922013-05-16 17:35:49 +0530413/* According to TS 05.08 Chapter 8.1.4 */
Harald Welteec8b4502010-02-20 20:34:29 +0100414uint8_t dbm2rxlev(int dbm)
415{
416 int rxlev = dbm + 110;
417
418 if (rxlev > 63)
419 rxlev = 63;
420 else if (rxlev < 0)
421 rxlev = 0;
422
423 return rxlev;
424}
425
Harald Weltecbc80622010-03-22 08:28:44 +0800426const char *gsm_band_name(enum gsm_band band)
Harald Welteaebe08c2010-03-04 10:39:17 +0100427{
428 switch (band) {
429 case GSM_BAND_450:
430 return "GSM450";
431 case GSM_BAND_480:
Sylvain Munaute10ae5b2010-07-04 11:41:36 +0200432 return "GSM480";
Harald Welteaebe08c2010-03-04 10:39:17 +0100433 case GSM_BAND_750:
434 return "GSM750";
435 case GSM_BAND_810:
436 return "GSM810";
437 case GSM_BAND_850:
438 return "GSM850";
439 case GSM_BAND_900:
440 return "GSM900";
441 case GSM_BAND_1800:
442 return "DCS1800";
443 case GSM_BAND_1900:
444 return "PCS1900";
445 }
446 return "invalid";
447}
448
449enum gsm_band gsm_band_parse(const char* mhz)
450{
451 while (*mhz && !isdigit(*mhz))
452 mhz++;
453
454 if (*mhz == '\0')
455 return -EINVAL;
456
Harald Welted3ff15f2010-03-07 18:23:47 +0100457 switch (strtol(mhz, NULL, 10)) {
Harald Welteaebe08c2010-03-04 10:39:17 +0100458 case 450:
459 return GSM_BAND_450;
460 case 480:
461 return GSM_BAND_480;
462 case 750:
463 return GSM_BAND_750;
464 case 810:
465 return GSM_BAND_810;
466 case 850:
467 return GSM_BAND_850;
468 case 900:
469 return GSM_BAND_900;
470 case 1800:
471 return GSM_BAND_1800;
472 case 1900:
473 return GSM_BAND_1900;
474 default:
475 return -EINVAL;
476 }
477}
478
Harald Welte622b7182010-03-07 17:50:21 +0100479enum gsm_band gsm_arfcn2band(uint16_t arfcn)
480{
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100481 int is_pcs = arfcn & ARFCN_PCS;
482
483 arfcn &= ~ARFCN_FLAG_MASK;
484
485 if (is_pcs)
Harald Welte622b7182010-03-07 17:50:21 +0100486 return GSM_BAND_1900;
487 else if (arfcn <= 124)
488 return GSM_BAND_900;
489 else if (arfcn >= 955 && arfcn <= 1023)
490 return GSM_BAND_900;
491 else if (arfcn >= 128 && arfcn <= 251)
492 return GSM_BAND_850;
493 else if (arfcn >= 512 && arfcn <= 885)
494 return GSM_BAND_1800;
495 else if (arfcn >= 259 && arfcn <= 293)
496 return GSM_BAND_450;
497 else if (arfcn >= 306 && arfcn <= 340)
498 return GSM_BAND_480;
499 else if (arfcn >= 350 && arfcn <= 425)
500 return GSM_BAND_810;
501 else if (arfcn >= 438 && arfcn <= 511)
502 return GSM_BAND_750;
503 else
504 return GSM_BAND_1800;
505}
506
Sylvain Munaut55720312012-12-11 23:44:41 +0100507struct gsm_freq_range {
508 uint16_t arfcn_first;
509 uint16_t arfcn_last;
510 uint16_t freq_ul_first;
511 uint16_t freq_dl_offset;
512 uint16_t flags;
513};
514
515static struct gsm_freq_range gsm_ranges[] = {
516 { 512, 810, 18502, 800, ARFCN_PCS }, /* PCS 1900 */
517 { 0, 124, 8900, 450, 0 }, /* P-GSM + E-GSM ARFCN 0 */
518 { 955, 1023, 8762, 450, 0 }, /* E-GSM + R-GSM */
519 { 128, 251, 8242, 450, 0 }, /* GSM 850 */
520 { 512, 885, 17102, 950, 0 }, /* DCS 1800 */
521 { 259, 293, 4506, 100, 0 }, /* GSM 450 */
522 { 306, 340, 4790, 100, 0 }, /* GSM 480 */
523 { 350, 425, 8060, 450, 0 }, /* GSM 810 */
524 { 438, 511, 7472, 300, 0 }, /* GSM 750 */
525 { /* Guard */ }
526};
527
Harald Welte622b7182010-03-07 17:50:21 +0100528/* Convert an ARFCN to the frequency in MHz * 10 */
529uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
530{
Sylvain Munaut55720312012-12-11 23:44:41 +0100531 struct gsm_freq_range *r;
532 uint16_t flags = arfcn & ARFCN_FLAG_MASK;
533 uint16_t freq10_ul = 0xffff;
534 uint16_t freq10_dl = 0xffff;
Harald Welte622b7182010-03-07 17:50:21 +0100535
Sylvain Munaut2a471ee2010-11-13 17:51:37 +0100536 arfcn &= ~ARFCN_FLAG_MASK;
537
Sylvain Munaut55720312012-12-11 23:44:41 +0100538 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
539 if ((flags == r->flags) &&
540 (arfcn >= r->arfcn_first) &&
541 (arfcn <= r->arfcn_last))
542 {
543 freq10_ul = r->freq_ul_first + 2 * (arfcn - r->arfcn_first);
544 freq10_dl = freq10_ul + r->freq_dl_offset;
545 break;
546 }
547 }
548
549 return uplink ? freq10_ul : freq10_dl;
550}
551
552/* Convert a Frequency in MHz * 10 to ARFCN */
553uint16_t gsm_freq102arfcn(uint16_t freq10, int uplink)
554{
555 struct gsm_freq_range *r;
556 uint16_t freq10_lo, freq10_hi;
557 uint16_t arfcn = 0xffff;
558
559 for (r=gsm_ranges; r->freq_ul_first>0; r++) {
560 /* Generate frequency limits */
561 freq10_lo = r->freq_ul_first;
562 freq10_hi = freq10_lo + 2 * (r->arfcn_last - r->arfcn_first);
563 if (!uplink) {
564 freq10_lo += r->freq_dl_offset;
565 freq10_hi += r->freq_dl_offset;
566 }
567
568 /* Check if this fits */
569 if (freq10 >= freq10_lo && freq10 <= freq10_hi) {
570 arfcn = r->arfcn_first + ((freq10 - freq10_lo) >> 1);
571 arfcn |= r->flags;
572 break;
573 }
574 }
Harald Welte622b7182010-03-07 17:50:21 +0100575
576 if (uplink)
Sylvain Munaut55720312012-12-11 23:44:41 +0100577 arfcn |= ARFCN_UPLINK;
578
579 return arfcn;
Harald Welte622b7182010-03-07 17:50:21 +0100580}
581
582void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
583{
584 time->fn = fn;
585 time->t1 = time->fn / (26*51);
586 time->t2 = time->fn % 26;
587 time->t3 = time->fn % 51;
588 time->tc = (time->fn / 51) % 8;
589}
590
591uint32_t gsm_gsmtime2fn(struct gsm_time *time)
592{
593 /* TS 05.02 Chapter 4.3.3 TDMA frame number */
594 return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
595}
Harald Weltea1c4f762010-05-01 11:59:42 +0200596
597/* TS 03.03 Chapter 2.6 */
598int gprs_tlli_type(uint32_t tlli)
599{
600 if ((tlli & 0xc0000000) == 0xc0000000)
601 return TLLI_LOCAL;
602 else if ((tlli & 0xc0000000) == 0x80000000)
603 return TLLI_FOREIGN;
604 else if ((tlli & 0xf8000000) == 0x78000000)
605 return TLLI_RANDOM;
606 else if ((tlli & 0xf8000000) == 0x70000000)
607 return TLLI_AUXILIARY;
608
609 return TLLI_RESERVED;
610}
Harald Weltec2263172010-06-01 10:47:07 +0200611
612uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
613{
614 uint32_t tlli;
615 switch (type) {
616 case TLLI_LOCAL:
617 tlli = p_tmsi | 0xc0000000;
618 break;
619 case TLLI_FOREIGN:
620 tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
621 break;
622 default:
623 tlli = 0;
624 break;
625 }
626 return tlli;
627}